PathProcessorStrokeAirbrush Class Reference

A path processor which renders paths as airbrushed strokes. More...

#include <ppairbsh.h>

Inheritance diagram for PathProcessorStrokeAirbrush:

PathProcessorStroke PathProcessor CCObject SimpleCCObject List of all members.

Public Member Functions

 PathProcessorStrokeAirbrush ()
 ~PathProcessorStrokeAirbrush ()
 Destructor.
virtual void ProcessPath (Path *pPath, RenderRegion *pRender, PathShape ShapePath=PATHSHAPE_PATH)
 Called by the RenderRegion to apply the path processing operation to the given path.
virtual BOOL WillChangeFillAndStrokeSeparately (void)
 Called by the RenderRegion to determine if this PathProcessorStrokeAirbrush affects the "fill" and "stroke" portions of the path separately. (Generally speaking, only fill/stroke providers will cause these two different "bits" of a path to be rendered separately). This call is made BEFORE this Processor's ProcessPath function will be called.
virtual BOOL IsDifferent (PathProcessorStroke *pOther)
 Equality operator.
virtual PathProcessorStrokeClone (void)
 To copy PathProcessorStrokeAirbrush or derived-class object.
virtual BOOL NeedsTransparency () const
ValueFunctionGetIntensityFunction (void)
 Sets the intensity function which will be used when rendering this airbrush. The function controls the intensity (opacity) of the airbrush at Position values where Position 0.0 represents the airbrush centreline, and 1.0 represents the maximum width.
void SetIntensityFunction (ValueFunction *pFunc)
 Sets the intensity function which will be used when rendering this airbrush. The function controls the intensity (opacity) of the airbrush at Position values where Position 0.0 represents the airbrush centreline, and 1.0 represents the maximum width.

Protected Member Functions

virtual INT32 GetNumSteps (View *pView, INT32 LineWidth)
 To get the number of steps for an airbrush stroke.
LOGPALETTEMakeGreyScalePalette (void)
 Obtain a greyscale palette.
virtual BOOL RenderAirBrush (Path *pPath, GRenderBitmap *pRegion, INT32 LineWidth, INT32 NumSteps, ValueFunction *pvValueFunction, RenderRegion *pDestRegion, PathShape ShapePath)
 Main Airbrush rendering loop.

Private Member Functions

 CC_DECLARE_DYNAMIC (PathProcessorStrokeAirbrush)

Private Attributes

ValueFunctionpIntensityFunction

Friends

class RenderRegion

Detailed Description

A path processor which renders paths as airbrushed strokes.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> & Richard
Date:
20/12/96
These classes are created by attributes (or similar) when rendered, and placed on a stack in the RenderRegion. Whenever RenderRegion::DrawPath is invoked to render a path, all stacked PathProcessors will be called in turn, and they call back to RenderRegion functions to render whatever they wish (usually a modified form of the original path).

This can be used to "filter" almost any rendering, but is mainly intended for use by stroke and fill providers, which replace input paths with more suitable shapes to be rendered.

See also:
RenderRegion::DrawPath; PathProcessor::ProcessPath

Definition at line 132 of file ppairbsh.h.


Constructor & Destructor Documentation

PathProcessorStrokeAirbrush::PathProcessorStrokeAirbrush  )  [inline]
 

Definition at line 139 of file ppairbsh.h.

00139 { pIntensityFunction = NULL; };

PathProcessorStrokeAirbrush::~PathProcessorStrokeAirbrush  ) 
 

Destructor.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
18/2/97

Definition at line 142 of file ppairbsh.cpp.

00143 {
00144     if (pIntensityFunction != NULL)
00145         delete pIntensityFunction;
00146 }


Member Function Documentation

PathProcessorStrokeAirbrush::CC_DECLARE_DYNAMIC PathProcessorStrokeAirbrush   )  [private]
 

PathProcessorStroke * PathProcessorStrokeAirbrush::Clone void   )  [virtual]
 

To copy PathProcessorStrokeAirbrush or derived-class object.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/2/97
Returns:
NULL if we're out of memory, else a pointer to a clone (exact copy) of this object

Reimplemented from PathProcessorStroke.

Definition at line 614 of file ppairbsh.cpp.

00615 {
00616     // Clone this object - this can be done by just creating a new one
00617     PathProcessorStrokeAirbrush *pClone = new PathProcessorStrokeAirbrush;
00618 
00619     if (pClone != NULL)
00620     {
00621         // And copy the (base class) parent-attribute pointer so we know when our
00622         // parent attribute is "current" in the render region.
00623         pClone->SetParentAttr(GetParentAttr());
00624 
00625         // And copy our intensity function, if any
00626         if (pIntensityFunction != NULL)
00627         {
00628             ValueFunction *pNewFunc = pIntensityFunction->Clone();
00629             pClone->SetIntensityFunction(pNewFunc);     // This is OK if it's NULL
00630         }
00631     }
00632 
00633     return(pClone);
00634 }

ValueFunction * PathProcessorStrokeAirbrush::GetIntensityFunction void   ) 
 

Sets the intensity function which will be used when rendering this airbrush. The function controls the intensity (opacity) of the airbrush at Position values where Position 0.0 represents the airbrush centreline, and 1.0 represents the maximum width.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
18/2/97
Returns:
NULL (if it fails horribly), else a pointer to the intensity ValueFunction
See also:
PathProcessorStrokeAirbrush::GetIntensityFunction

Definition at line 871 of file ppairbsh.cpp.

00872 {
00873     if (pIntensityFunction == NULL)
00874         pIntensityFunction = new ValueFunctionRampS(1.0, 0.0);
00875 
00876     return(pIntensityFunction);
00877 }

INT32 PathProcessorStrokeAirbrush::GetNumSteps View pView,
INT32  LineWidth
[protected, virtual]
 

To get the number of steps for an airbrush stroke.

Author:
Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/2/97
Parameters:
pView - Relevant View (for zoom info) [INPUTS] LineWidth - LineWidth in millipoints
Returns:
Number of steps which will produce a smooth graduated airbrush for this line at the current zoom, etc...

Definition at line 651 of file ppairbsh.cpp.

00652 {
00653     if(pView == NULL)
00654         return 1;
00655 
00656     // Find out how many millipoints 1 pixel is
00657     const INT32 spw = pView->GetScaledPixelWidth().MakeLong();
00658     const INT32 sph = pView->GetScaledPixelHeight().MakeLong();
00659     const MILLIPOINT OnePixel = min(spw, sph);
00660     TRACEUSER( "Richard", _T("1 pixel = %d\n"), OnePixel);
00661 
00662     if (OnePixel <= 0)
00663         return(1);
00664 
00665     // Now work out how many steps to render. The fewer steps, the faster we go, but this
00666     // trades off against quality. Because we start in the centre and increase in both
00667     // directions, we need to divide line width by the size of 2 pixels to get a step per pixel.
00668     // However, 3 is used because it means each ring of the airbrush is 1.5 pixels wider than the
00669     // last, which, with anti-aliasing, gives a very smooth effect. Going up to 4 makes each one
00670     // 2 pixels, and you can begin to see tree-ring effects in the airbrush.
00671     INT32 NumSteps = (INT32)(LineWidth / (OnePixel * 3));
00672 
00673     // Limit it to a sensible range 
00674     if(NumSteps < 1)
00675         NumSteps = 1;
00676     if(NumSteps > MaxAirbrushSteps)
00677         NumSteps = MaxAirbrushSteps;
00678 
00679     TRACEUSER( "Richard", _T("NumSteps = %d\n"), NumSteps);
00680 
00681     return NumSteps;
00682 }

BOOL PathProcessorStrokeAirbrush::IsDifferent PathProcessorStroke pOther  )  [virtual]
 

Equality operator.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/2/97
Parameters:
pOther - The other PathProcessorStroke [INPUTS]
Returns:
TRUE if they're considered different, FALSE if they are equivalent
Notes: The base class implementation compares the runtime classes of the 2 objects to see if they are different classes. If they are the same class, it assumes they're cnsidered equal - derived classes should override this behaviour if further comparisons are necessary.

Reimplemented from PathProcessorStroke.

Definition at line 580 of file ppairbsh.cpp.

00581 {
00582     ERROR3IF(pOther == NULL, "Illegal NULL param");
00583 
00584     if (GetRuntimeClass() != pOther->GetRuntimeClass())
00585         return(TRUE);
00586 
00587     PathProcessorStrokeAirbrush *pOtherAir = (PathProcessorStrokeAirbrush *)pOther;
00588 
00589     ValueFunction *pMyFunc    = GetIntensityFunction();
00590     ValueFunction *pOtherFunc = pOtherAir->GetIntensityFunction();
00591     if (pMyFunc == NULL || pOtherFunc == NULL)
00592         return(TRUE);
00593 
00594     // We're the same if we share the same intensity function
00595     return(pMyFunc->IsDifferent(pOtherFunc));
00596 }

LOGPALETTE * PathProcessorStrokeAirbrush::MakeGreyScalePalette void   )  [protected]
 

Obtain a greyscale palette.

Author:
Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/2/97
Returns:
A 256 entry greyscale palette, or NULL if it failed
Notes: A static palette is cached to save building one for every redraw

Definition at line 699 of file ppairbsh.cpp.

00700 {
00701     static BYTE Pal[sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY)];
00702     static LOGPALETTE *pPal = NULL;
00703     
00704     if (pPal == NULL)       // Only fill in the palette the first time we're called
00705     {
00706         pPal = (LOGPALETTE *) Pal;
00707 
00708         pPal->palVersion = 0x300;
00709         pPal->palNumEntries = 256;
00710         for (INT32 i = 0; i < 256; i++)
00711         {
00712             pPal->palPalEntry[i].peRed      = i;
00713             pPal->palPalEntry[i].peGreen    = i;
00714             pPal->palPalEntry[i].peBlue     = i;
00715             pPal->palPalEntry[i].peFlags    = 0;
00716         }
00717     }
00718 
00719     return pPal;
00720 }

virtual BOOL PathProcessorStrokeAirbrush::NeedsTransparency void   )  const [inline, virtual]
 

Reimplemented from PathProcessorStroke.

Definition at line 156 of file ppairbsh.h.

00156 {return TRUE;};

void PathProcessorStrokeAirbrush::ProcessPath Path pPath,
RenderRegion pRender,
PathShape  ShapePath = PATHSHAPE_PATH
[virtual]
 

Called by the RenderRegion to apply the path processing operation to the given path.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/2/97
The PathProcessorStrokeAirbrush class changes the stroking (only) of paths passed into it.

Notes: * When rendering a path, always pass in your 'this' pointer to RenderRegion::DrawPath, so that you don't start an infinite recursion!

To stop rendering of the path, simply return without calling the RR

To render this path unchanged, simply call directly back to the RR: pRender->DrawPath(pPath, this);

Only affect the fill of this path if pPath->IsFilled

Only affect the stroke of this path if pPath->IsStroked

If converting a path into a "filled path" for stroking, the output path should be rendered with IsStroked=FALSE or it'll get a line around the outside!

Reimplemented from PathProcessorStroke.

Definition at line 214 of file ppairbsh.cpp.

00217 {
00218     PORTNOTETRACE("other","PathProcessorStrokeAirbrush::ProcessPath - do nothing");
00219 #ifndef EXCLUDE_FROM_XARALX
00220     ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params");
00221 
00222     // --- If the provided path is not stroked, then we'll just pass it straight through
00223     // We also don't touch it if we're doing EOR rendering, or click regions
00224     // BLOCK
00225     {
00226         StrokeColourAttribute *pStrokeColour = (StrokeColourAttribute *) pRender->GetCurrentAttribute(ATTR_STROKECOLOUR);
00227         if (pRender->DrawingMode != DM_COPYPEN || pRender->IsHitDetect()
00228             || !pPath->IsStroked || pStrokeColour == NULL || pStrokeColour->Colour.IsTransparent())
00229         {
00230             pRender->DrawPath(pPath, this, ShapePath);
00231             return;
00232         }
00233     }
00234 
00235     // --- If the quality is set low, strokes are just rendered as centrelines
00236     // BLOCK
00237     {
00238         QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY);
00239         if (pQuality != NULL && pQuality->QualityValue.GetLineQuality() != Quality::FullLine)
00240         {
00241             pRender->DrawPath(pPath, this, ShapePath);
00242             return;
00243         }
00244     }
00245 
00246     // --- If the attribute which created us is not the current StrokeType attribute, then
00247     // we have been overridden by a different stroke type, so we do nothing.
00248     // BLOCK
00249     {
00250         StrokeTypeAttrValue *pTypeAttr = (StrokeTypeAttrValue *) pRender->GetCurrentAttribute(ATTR_STROKETYPE);
00251         if (pTypeAttr != NULL && pTypeAttr != GetParentAttr())
00252         {
00253             pRender->DrawPath(pPath, this, ShapePath);
00254             return;
00255         }
00256     }
00257 
00258     // --- Get the current line width from the render region
00259     // In case of failure, we initialise with suitable defaults
00260     INT32 LineWidth = 5000;
00261     // BLOCK
00262     {
00263         LineWidthAttribute *pWidthAttr = (LineWidthAttribute *) pRender->GetCurrentAttribute(ATTR_LINEWIDTH);
00264         if (pWidthAttr != NULL)
00265             LineWidth = pWidthAttr->LineWidth;
00266     }
00267 
00268     // Obtain an optimal number of steps for the line
00269     // When printing, we do heaps of steps to get top quality out the other end
00270     View *pView = pRender->GetRenderView();
00271     ERROR3IF(pView == NULL, "No render view?!");
00272 
00273     INT32 NumSteps = MaxAirbrushSteps;
00274     if (!pRender->IsPrinting())
00275         GetNumSteps(pView, LineWidth);
00276 
00277     // --- Now, create a transparency mask bitmap for the airbrush
00278     Spread *pSpread = pRender->GetRenderSpread();
00279 //  ERROR3IF(pSpread == NULL, "No render spread!?");    // This can happen, rendering into a gallery
00280 
00281     // Get the render region's clip rectangle in Spread Coords. We don't need to
00282     // render anything bigger than this size, so it is the upper limit on our bitmap area.
00283     DocRect ClipRegion = pRender->GetClipRect();
00284 
00285     // Intersect this with the path bounding rectangle to get the actual region we need to redraw
00286     // The smaller this is, the faster we go and the less memory we use.
00287     //DocRect PathRect = pPath->GetBoundingRect();
00288     DocRect PathRect = pPath->GetBlobRect();
00289     PathRect.Inflate(LineWidth);
00290 
00291     BOOL Intersects = ClipRegion.IsIntersectedWith(PathRect);
00292     if(!Intersects)
00293     {
00294         // Don't bother drawing anything - it's clipped out
00295         return;
00296     }
00297 
00298     ClipRegion = ClipRegion.Intersection(PathRect);
00299 
00300     // Round the ClipRegion edges up so they all lie exactly on screen pixel boundaries.
00301     // If we don't do this, then there can be a sub-pixel rounding error between the ClipRegion
00302     // and the actual bitmap size, so that the bitmap is scaled slightly when we plot it.
00303     // By making sure it's pixelised, we guarantee that the bitmap & clipregion are exactly equal sizes.
00304     // (It doesn't matter if the bitmap is a bit bigger than necessary)
00305     ClipRegion.Inflate(pRender->GetScaledPixelWidth());
00306     ClipRegion.lo.Pixelise(pView);
00307     ClipRegion.hi.Pixelise(pView);
00308 
00309     // Get the current view's rendering matrix and view scale
00310     Matrix ConvMatrix = pRender->GetMatrix();//pView->ConstructRenderingMatrix(pSpread);
00311     FIXED16 ViewScale = pView->GetViewScale();
00312 
00313     // Generate a 256-colour greyscale palette
00314     LOGPALETTE *pPalette = MakeGreyScalePalette();
00315     if(pPalette == NULL)
00316     {
00317         pRender->DrawPath(pPath, this, ShapePath);
00318         return;
00319     }
00320 
00321     // Work out the DPI to use. Rather than just asking for PixelWidth or DPI from the
00322     // render region, we have to do a load of non-object-oriented stuff instead...
00323     double dpi = 96.0;
00324     if (pRender->IsPrinting())
00325     {
00326         // we are printing, so ask the print options
00327         PrintControl *pPrintControl = pView->GetPrintControl();
00328         if (pPrintControl != NULL)
00329             dpi = (double) pPrintControl->GetDotsPerInch();
00330     }
00331     else if (IS_A(pRender, CamelotEPSRenderRegion))
00332     {
00333         // Use DPI as set in EPS export options dialog.
00334         dpi = (double) EPSFilter::XSEPSExportDPI;
00335     }
00336     else
00337     {
00338         ERROR3IF(pRender->GetPixelWidth() <= 0, "Stupid (<1 millipoint) Pixel Width!");
00339         if (pRender->GetPixelWidth() > 0)
00340             dpi = (double) (72000.0 / (double)pRender->GetPixelWidth());
00341     }
00342 
00343     GRenderBitmap *pMaskRegion = new GRenderBitmap(ClipRegion, ConvMatrix, ViewScale, 8, dpi,
00344                                                     pRender->IsPrinting(), XARADITHER_ORDERED_GREY,
00345                                                     pPalette, FALSE);
00346     if (pMaskRegion == NULL)
00347     {
00348         pRender->DrawPath(pPath, this, ShapePath);
00349         return;
00350     }
00351 
00352     BOOL PathIsFilled = FALSE;      // Will be set TRUE if this path should be filled at the bottom of the function
00353 
00354     //BLOCK
00355     {
00356         // Change the GDraw context in this render region so as to preserve the state
00357         // of the main render region. This is because GRenderRegions currently use
00358         // a single static GDrawContext! This also sets it up with a nice greyscale palette
00359         // so that we get the output we desire.
00360         pMaskRegion->UseGreyscaleContextDangerous();
00361 
00362         // Attach our DC to the view and render region...
00363         if (pMaskRegion->AttachDevice(pView, NULL, pSpread))
00364         {
00365             pMaskRegion->StartRender();
00366 
00367             // We must save & restore the attribute state around all our rendering because
00368             // attributes otherwise stay on the renderstack until we delete the RndRgn, and as our
00369             // ones are on the program stack, they will have ceased to exist before then, which
00370             // makes for a wicked explosion.
00371             pMaskRegion->SaveContext();
00372 
00374             // --- Main Airbrush rendering loop
00375 
00376             // Make sure we've got an intensity function to use. This will create a new one if necessary
00377             ValueFunction *pvValueFunction = GetIntensityFunction();
00378             if (pvValueFunction == NULL)
00379             {
00380                 ERROR3("Failed to set an intensity function on an airbrush stroke");
00381                 pRender->DrawPath(pPath, this, ShapePath);
00382                 return;
00383             }
00384 
00385 
00386             if(!RenderAirBrush(pPath, pMaskRegion, LineWidth, NumSteps, pvValueFunction,
00387                                pRender, ShapePath))
00388             {
00389                 // Airbrush failed - just render the path without the airbrush effect
00390                 pRender->DrawPath(pPath, this, ShapePath);
00391                 return;
00392             }
00393 
00394             pMaskRegion->RestoreContext();
00395 
00396             // --- ClipRect test code
00397 
00399 
00400 
00401             // --- We have drawn the airbrushed stroke - now, if the path is filled, we
00402             // will render the filled area, so that in semi-transparent cases, the
00403             // stroke will not "show through" from behind the filled area.          
00404             if (pPath->IsFilled)
00405             {
00406                 ColourFillAttribute *pCFAttr = (ColourFillAttribute   *) pRender->GetCurrentAttribute(ATTR_FILLGEOMETRY);
00407                 if (pCFAttr != NULL && (!pCFAttr->Colour.IsTransparent() || pCFAttr->IsABitmapFill()))
00408                 {
00409                     PathIsFilled = TRUE;
00410 
00411                     pMaskRegion->SaveContext();
00412 
00413                     ColourFillAttribute *pFillAttr = NULL;
00414                     FillMappingAttribute *pMapAttr = NULL;
00415 
00416                     // Obtain the object's transparent fill geometry
00417                     TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY);
00418                     if (pTransAttr != NULL)
00419                     {
00420                         // Get a non-transparent version of the fill geometry
00421                         pFillAttr = pTransAttr->MakeSimilarNonTranspFillGeometry(1.0);
00422                         
00423                         // Convert a fill mapping
00424                         TranspFillMappingAttribute *pTransMapAttr = (TranspFillMappingAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLMAPPING);
00425                         if(pTransMapAttr != NULL)
00426                             pMapAttr = pTransMapAttr->MakeSimilarNonTranspFillMapping();
00427                     }
00428 
00429                     // Setup region and draw path into it
00430                     if (pFillAttr != NULL)
00431                     {
00432                         pMaskRegion->SetFillGeometry(pFillAttr, TRUE);
00433 
00434                         if(pMapAttr != NULL)
00435                             pMaskRegion->SetFillMapping(pMapAttr, TRUE);
00436                     }
00437                     else
00438                         pMaskRegion->SetFillColour(DocColour(0, 0, 0));
00439 
00440                     pMaskRegion->SetLineColour(DocColour(COLOUR_TRANS));
00441                     pMaskRegion->DrawPath(pPath, NULL, ShapePath);
00442 
00443                     pMaskRegion->RestoreContext();
00444                 }
00445             }
00446 
00447             pMaskRegion->StopRender();
00448         }
00449 
00450         pMaskRegion->StopUsingGreyscaleContextDangerous();
00451     }
00452 
00453     // Extract the transparency mask bitmap from the render region
00454     OILBitmap *pOilBmp = pMaskRegion->ExtractBitmap();
00455 
00456     // We no longer need the RenderRegion, so scrap it.
00457     delete pMaskRegion;
00458     pMaskRegion = NULL;
00459     pPalette = NULL;
00460 
00461     // Now, render a rectangle to the output render region, using the transparency mask
00462     if (pOilBmp == NULL)
00463         return;
00464 
00465     KernelBitmap *pMask = new KernelBitmap(pOilBmp, TRUE);
00466 
00467     if (pMask != NULL)
00468     {
00469         // Make sure the bitmap knows it's already a greyscale, else it will spend a lot of
00470         // time "converting" itself to a greyscale, and what's more, corrupting the grey levels
00471         // so that 255 (invisible) becomes 254 (slightly visible). Arrrrrgh!
00472         pMask->SetAsGreyscale();
00473 
00474         // Create a transparency attribute from our mask bitmap
00475         BitmapTranspFillAttribute Trans;
00476 
00477         // We don't call pTrans->AttachBitmap because it seems to be stupid, and causes ructions
00478         // when we try to attach a temporary bitmap. We thus do the same thing, but avoiding
00479         // its attempts to automatically screw us about.
00480         Trans.BitmapRef.Detach();
00481         Trans.BitmapRef.SetBitmap(pMask);
00482 
00483         Trans.SetStartPoint(&ClipRegion.lo);
00484         DocCoord EndPoint(ClipRegion.hi.x, ClipRegion.lo.y);
00485         Trans.SetEndPoint(&EndPoint);
00486         DocCoord EndPoint2(ClipRegion.lo.x, ClipRegion.hi.y);
00487         Trans.SetEndPoint2(&EndPoint2);
00488 
00489         UINT32 TValue = 0;
00490         Trans.SetStartTransp(&TValue);
00491         TValue = 255;
00492         Trans.SetEndTransp(&TValue);
00493 
00494         // Use the same transparency type as is set on the object being rendered (if any)
00495         {
00496             TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY);
00497 
00498             if (pTransAttr != NULL)
00499                 Trans.SetTranspType(pTransAttr->GetTranspType());
00500             else
00501                 Trans.SetTranspType(TT_Mix);        // By default, we'll use Mix transparency
00502             
00503         }
00504 
00505         // --- OK, we finally got here! Render the stroke, using the transparency mask we just made
00506         pRender->SaveContext();
00507 
00508             Trans.Render(pRender);
00509 
00510             // Render the path. If it is filled, then we render the entire thing (fill & stroke) using
00511             // the current fill geometry (to get a shadow/feather effect)
00512             if (PathIsFilled)
00513             {
00514                 // Render the entire thing (fill & stroke) in one go. We render a rectangle over the cliprect
00515                 // so that we do everything in one go (we can't render the fill &7 stroke separately, or
00516                 // the transparency will overlap & it'll look wrong)
00517                 pRender->SetLineColour(DocColour(COLOUR_TRANS));        // Don't render a line
00518 
00519                 Path Rect;
00520                 Rect.Initialise();
00521                 Rect.AddMoveTo(ClipRegion.lo);
00522                 Rect.AddLineTo(DocCoord(ClipRegion.hix, ClipRegion.loy));
00523                 Rect.AddLineTo(ClipRegion.hi);
00524                 Rect.AddLineTo(DocCoord(ClipRegion.lox, ClipRegion.hiy));
00525                 Rect.AddLineTo(ClipRegion.lo);
00526                 Rect.IsFilled  = TRUE;
00527                 Rect.IsStroked = FALSE;
00528                 pRender->DrawPath(&Rect, this, ShapePath);
00529             }
00530             else
00531             {
00532                 // Otherwise, create a filled-outline path for the entire stroke, and render it
00533                 // !!!!****ToDo - for now, strokes always render flat-filled with the stroke colour
00534                 StrokeColourAttribute *pStrokeColour = (StrokeColourAttribute *) pRender->GetCurrentAttribute(ATTR_STROKECOLOUR);
00535                 if (pStrokeColour != NULL)
00536                     pRender->SetFillColour(pStrokeColour->Colour);
00537 
00538                 // Fill the holes
00539                 pRender->SetWindingRule(NonZeroWinding);
00540 
00541                 Path *pOutput = CreateVarWidthStroke(pPath, pRender, LineWidth);
00542                 if (pOutput != NULL)
00543                 {
00544                     pRender->DrawPath(pOutput, NULL, ShapePath);
00545                     delete pOutput;
00546                     pOutput = NULL;
00547                 }
00548             }
00549 
00550         pRender->RestoreContext();
00551 
00552         // Delete the kernel bitmap. This auto-deletes the OIL bitmap for us
00553         delete pMask;
00554     }
00555 #endif
00556 }

BOOL PathProcessorStrokeAirbrush::RenderAirBrush Path pPath,
GRenderBitmap pRegion,
INT32  LineWidth,
INT32  NumSteps,
ValueFunction pvValueFunction,
RenderRegion pDestRegion,
PathShape  ShapePath
[protected, virtual]
 

Main Airbrush rendering loop.

Author:
Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/2/97
Parameters:
pPath - Path to render [INPUTS] pRegion - Region to render the airbrush tranparency mask into LineWidth - Maximum linewidth NumSteps - Number of Airbrush graduation steps pvValueFunction - Value function for the edge rampyness pDestRegion - Region we are rendering the airbrush to in the end (needed to get current stroke attributes from) ShapePath - The PathShape of the current shape.
Returns:
TRUE if things went ok

Definition at line 746 of file ppairbsh.cpp.

00749 {
00750     PORTNOTETRACE("other","PathProcessorStrokeAirbrush::RenderAirBrush - do nothing");
00751 #ifndef EXCLUDE_FROM_XARALX
00752     if(pPath == NULL || pRegion == NULL || NumSteps <= 0)
00753     {
00754         ERROR3("PathProcessorStrokeAirbrush::RenderAirBrush given dodgy params");
00755         return FALSE;
00756     }
00757 
00758     // Fill the holes
00759     pRegion->SetWindingRule(NonZeroWinding);
00760 
00761     // Precalculate the trapezoid structure for stroking with
00762     TrapsList *pTrapezoids = PrepareTrapsForStroke(pPath, pDestRegion, LineWidth);
00763     if (pTrapezoids == NULL)
00764         return FALSE;
00765 
00766     INT32 LastIntensity = 255;
00767 
00768     // Use the previously obtained number of steps for the graduation
00769     for(INT32 i = NumSteps; i > 0; i--)
00770     {
00771         INT32 Intensity = 0;
00772         
00773         // What intensity should we use ?
00774         if(pvValueFunction == NULL)
00775         {
00776             // A linear ramp
00777             Intensity = (255 * i) / NumSteps;
00778         }
00779         else
00780         {
00781             // Use the value function
00782             double Position = (double)i / (double)NumSteps;         
00783             Intensity = (INT32)((1.0 - pvValueFunction->GetValue(Position)) * 255.0);
00784         }
00785 
00786         // Bit dodgy for 1st stroke, but then it shouldn't be the same as the last
00787         if(LastIntensity != Intensity)
00788         {                              
00789             LastIntensity = Intensity;
00790 
00791             if(Intensity != 255)
00792             {
00793                 // --- Create the stroke outline by calling our helper function
00794                 INT32 ThisWidth = (LineWidth * i) / NumSteps;
00795 
00796                 Path *pOutput = CreateVarWidthStroke(pPath, pDestRegion, ThisWidth, pTrapezoids);
00797                 if(pOutput != NULL)
00798                 {
00799                     ColourFillAttribute *pFillAttr = NULL;
00800                     FillMappingAttribute *pMapAttr = NULL;
00801 
00802                     if(pDestRegion != NULL)
00803                     {
00804                         // Obtain the object's transparent fill geometry
00805                         TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pDestRegion->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY);
00806                         if (pTransAttr == NULL)
00807                         {
00808                             // There is no transparency on this object - just use a flat transparency
00809                             pFillAttr = new FlatFillAttribute;
00810                             if (pFillAttr)
00811                                 pFillAttr->SetStartColour(&DocColour(Intensity, Intensity, Intensity));
00812                         }
00813                         else
00814                         {
00815                             // Get a non-transparent version of the fill geometry
00816                             pFillAttr = pTransAttr->MakeSimilarNonTranspFillGeometry(1.0 - ((double)(Intensity) / 255.0));
00817                             
00818                             // Convert a fill mapping
00819                             TranspFillMappingAttribute *pTransMapAttr = (TranspFillMappingAttribute *) pDestRegion->GetCurrentAttribute(ATTR_TRANSPFILLMAPPING);
00820                             if(pTransMapAttr != NULL)
00821                                 pMapAttr = pTransMapAttr->MakeSimilarNonTranspFillMapping();
00822                         }
00823                     }
00824 
00825                     // Setup region and draw path into it
00826                     if(pFillAttr != NULL)
00827                     {
00828                         pRegion->SetFillGeometry(pFillAttr, TRUE);
00829 
00830                         if(pMapAttr != NULL)
00831                             pRegion->SetFillMapping(pMapAttr, TRUE);
00832                     }
00833                     else
00834                         pRegion->SetFillColour(DocColour(Intensity, Intensity, Intensity));
00835                     
00836                     pRegion->DrawPath(pOutput, NULL, ShapePath);
00837                     delete pOutput;
00838                 }
00839             }
00840         }
00841     }
00842 
00843     delete pTrapezoids;
00844 
00845     return TRUE;
00846 #else
00847     return FALSE;
00848 #endif
00849 }

void PathProcessorStrokeAirbrush::SetIntensityFunction ValueFunction pFunc  ) 
 

Sets the intensity function which will be used when rendering this airbrush. The function controls the intensity (opacity) of the airbrush at Position values where Position 0.0 represents the airbrush centreline, and 1.0 represents the maximum width.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
18/2/97
Parameters:
pFunc - The new ValueFunction to use [INPUTS] A value of NULL will set the airbrush to the default setting (using an ValueFunctionRampS from 1.0 to 0.0)
See also:
PathProcessorStrokeAirbrush::GetIntensityFunction

Definition at line 901 of file ppairbsh.cpp.

00902 {
00903     if (pIntensityFunction != NULL)
00904         delete pIntensityFunction;
00905 
00906     pIntensityFunction = pFunc;
00907 }

BOOL PathProcessorStrokeAirbrush::WillChangeFillAndStrokeSeparately void   )  [virtual]
 

Called by the RenderRegion to determine if this PathProcessorStrokeAirbrush affects the "fill" and "stroke" portions of the path separately. (Generally speaking, only fill/stroke providers will cause these two different "bits" of a path to be rendered separately). This call is made BEFORE this Processor's ProcessPath function will be called.

Author:
Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
Date:
31/12/96
Returns:
TRUE
If the caller gets a TRUE back, the stroke and fill paths will be rendered separately.

Notes: Base class implementation returns FALSE. Derived Stroke and Fill processors (such as this one) override this method to return TRUE.

Reimplemented from PathProcessorStroke.

Definition at line 173 of file ppairbsh.cpp.

00174 {
00175     return(FALSE);
00176 }


Friends And Related Function Documentation

friend class RenderRegion [friend]
 

Reimplemented from PathProcessorStroke.

Definition at line 134 of file ppairbsh.h.


Member Data Documentation

ValueFunction* PathProcessorStrokeAirbrush::pIntensityFunction [private]
 

Definition at line 178 of file ppairbsh.h.


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 03:59:39 2007 for Camelot by  doxygen 1.4.4