ppbrush.cpp

Go to the documentation of this file.
00001 // $Id: ppbrush.cpp 1328 2006-06-15 19:23:45Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 /*
00099 // */
00100 
00101 // PathProcessor Brush implementation
00102 
00103 #include "camtypes.h"
00104 #include "ppbrush.h"
00105 #include "brshcomp.h"
00106 #include "pathproc.h"
00107 //#include "doccoord.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "attrmap.h"
00110 #include "brushref.h"
00111 #include "ndbldpth.h"
00112 //#include "fixed16.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "matrix.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "fillval.h"  // for my traces, may remove  - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "qualattr.h"
00117 // Native file load/save includes
00118 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 #include "cxftags.h"
00122 //#include "grndbrsh.h" // for real time brush drawing
00123 //#include "rik.h"      // for the strings
00124 #include "progress.h"
00125 #include "mtrand.h"
00126 #include "pen.h"
00127 #include "brshbeca.h"
00128 #include "lineattr.h"
00129 //#include "colourix.h"
00130 #include "cnamecol.h"
00131 //#include "swfrndr.h"
00132 #include "samplist.h"
00133 #include "scanrr.h"
00134 #include "valfunc.h"
00135 #include "strkattr.h"
00136 //#include "offscrn.h"
00137 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00138 
00139 #include "ophist.h"
00140 #include "vectrndr.h"
00141 
00142 DECLARE_SOURCE("$Revision: 1328 $");
00143 
00144 CC_IMPLEMENT_DYNAMIC(PathProcessorBrush, PathProcessor);
00145 PORTNOTE("other","Removed BrushSubRenderContext - derived from SubRenderContext")
00146 #ifndef EXCLUDE_FROM_XARALX
00147 CC_IMPLEMENT_DYNCREATE(BrushSubRenderContext, SubRenderContext);
00148 #endif
00149 
00150 // Declare smart memory handling in Debug builds
00151 #define new CAM_DEBUG_NEW
00152 
00153 const double MAX_RANDOM_FACTOR = 2.0;
00154 const double MIN_RANDOM_FACTOR = 1.0;
00155 const double MIN_ROTATION_RANDOM_FACTOR = 1.0;
00156 const double MAX_ROTATION_RANDOM_FACTOR = 1.0;
00157 const UINT32 MAX_RANDOM_AMOUNT = 100;
00158 const UINT32 MIN_RANDOM_AMOUNT = 0;
00159 
00160 // Define this if you want to use Phil's new RenderBrushAtPoint function
00161 // to fix accuracy/repeatability problems with brush rendering
00162 #define NEW_RENDERBRUSHATPOINT
00163 
00164 /********************************************************************************************
00165 
00166 >   PathProcessorBrush::PathProcessorBrush()
00167 
00168     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00169     Created:    13/12/99
00170 
00171     Purpose:    Constructor
00172 
00173 ********************************************************************************************/
00174 
00175 PathProcessorBrush::PathProcessorBrush()
00176 {
00177     m_AltValue = 0;
00178     m_BrushSpacing = 10000;
00179     m_bScaleToLineWidth = TRUE;
00180     m_LineWidth = -1;
00181     m_pParentAttr = NULL;
00182 
00183     m_BrushScaling          = 1.0;
00184     m_BrushScalingIncr      = 1.0;
00185     m_BrushScalingIncrConst = 0.0;
00186     m_BrushScalingMaxRand   = 0;
00187     m_BrushScalingRandSeed  = 0;
00188     m_ScalingMaxPressure    = 0;
00189 
00190     m_BrushSpacingIncrProp  = 1.0;
00191     m_BrushSpacingIncrConst = 0;
00192     m_BrushSpacingMaxRand   = 0;
00193     m_BrushSpacingRandSeed  = 5;
00194     m_SpacingMaxPressure    = 0;
00195 
00196     m_RotationMaxRand       = 0;
00197     m_RotationRandSeed      = 0;
00198 #ifdef USE_MTRNG
00199     m_pSpacingRNG           = NULL;
00200     m_pScalingRNG           = NULL;
00201     m_pOffsetTypeRNG        = NULL;
00202     m_pOffsetValueRNG       = NULL;
00203     m_pRotationRNG          = NULL;
00204     m_pSaturationRNG        = NULL;
00205     m_pHueRNG               = NULL;
00206     m_pSequenceRNG          = NULL;
00207 #endif
00208     m_PathOffsetIncrProp = 1.0;
00209     m_PathOffsetIncrConst = 0;
00210 
00211     m_SequenceType            = SEQ_FORWARD;
00212     m_SequenceRandSeed        = 0;
00213 
00214     m_OffsetTypeRandSeed      = 0;
00215     m_bUseLocalFillColour = FALSE;
00216     m_bUseLocalTransp     = FALSE;
00217     m_bUseNamedColours    = TRUE;
00218     m_CurrentPressure.m_Pressure = MAXPRESSURE / 2;
00219     m_bCalculateRect  = FALSE;
00220 
00221     m_RotateAngle = 0.0;
00222     m_RotAngleIncrProp = 1.0;
00223     m_RotAngleIncrConst = 0;
00224     
00225     m_BrushSatMaxRand = 0;
00226     m_BrushSatRandSeed = 0;
00227     m_BrushHueMaxRand = 0;
00228     m_BrushHueRandSeed = 0;
00229     m_BrushHueIncrement = 1.0;
00230     m_BrushSatIncrement = 1.0;
00231 
00232     m_LastOffset = 0;   
00233     m_LastScaling = 10000;
00234     m_LastObject = 0;
00235 
00236     m_pObjectRendered = NULL;
00237     m_pLastScalingRendered = NULL;
00238     m_pLastTangent  = NULL;
00239     m_pLastRotation = NULL;
00240 
00241     m_BrushTransparency = 100;
00242     m_TranspMaxPressure = 0;
00243 
00244     // we have to allocate our 'dummy' transparency attribute, which we must use in order to 
00245     // prevent transparency from one blendpath being 'carried over' to other blendpaths.
00246     m_pDefaultTransp = NULL;
00247     
00248     m_pDefaultTransp = new AttrFlatTranspFill;
00249     if (m_pDefaultTransp != NULL)
00250     {
00251         TranspFillAttribute* pVal = (TranspFillAttribute*)m_pDefaultTransp->GetAttributeValue();
00252         if (pVal != NULL)
00253             pVal->Transp = 0;
00254     }
00255 }
00256 
00257 
00258 /********************************************************************************************
00259 
00260 >   PathProcessorBrush::~PathProcessorBrush()
00261 
00262     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00263     Created:    13/12/99
00264 
00265     Purpose:    Destructor - basically this just wipes the caches. 
00266                 
00267 
00268 ********************************************************************************************/
00269 
00270 PathProcessorBrush::~PathProcessorBrush()
00271 {
00272 
00273 #ifdef USE_MTRNG
00274     if (m_pSpacingRNG != NULL)
00275         delete m_pSpacingRNG;
00276     if (m_pScalingRNG != NULL)
00277         delete m_pScalingRNG;
00278     if (m_pOffsetTypeRNG != NULL)
00279         delete m_pOffsetTypeRNG;
00280     if (m_pOffsetValueRNG != NULL)
00281         delete m_pOffsetValueRNG;
00282     if (m_pRotationRNG != NULL)
00283         delete m_pRotationRNG;
00284     if (m_pSaturationRNG != NULL)
00285         delete m_pSaturationRNG;
00286     if (m_pHueRNG != NULL)
00287         delete m_pHueRNG;
00288     if (m_pSequenceRNG != NULL)
00289         delete m_pSequenceRNG;
00290 #endif
00291 
00292     if (m_pDefaultTransp != NULL)
00293         delete m_pDefaultTransp;
00294 }
00295 
00296 /********************************************************************************************
00297 
00298 >   virtual BOOL PathProcessorBrush::WillChangeFillAndBrushSeparately(void)
00299 
00300     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00301     Created:    13/12/99
00302 
00303     Returns:    ???? haven't decided yet
00304 
00305     Purpose:    Called by the RenderRegion to determine if this PathProcessorBrush affects
00306                 the "fill" and "Brush" portions of the path separately. (Generally
00307                 speaking, only fill/Brush providers will cause these two different
00308                 "bits" of a path to be rendered separately). This call is made BEFORE
00309                 this Processor's ProcessPath function will be called.
00310 
00311                 If the caller gets a TRUE back, the Brush and fill paths will be
00312                 rendered separately.
00313 
00314     Notes:      Actually this call serves no purpose in this derived class.
00315 
00316 ********************************************************************************************/
00317 
00318 BOOL PathProcessorBrush::WillChangeFillAndBrushSeparately(void)
00319 {
00320     return(TRUE);
00321 }
00322 
00323 
00324 /********************************************************************************************
00325 
00326 >   virtual BOOL PathProcessorBrush::IsAPathProcessorBrush()
00327 
00328     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00329     Created:    13/12/99
00330 
00331     Returns:    TRUE!
00332 
00333     Purpose:    Virtual identifier
00334 ********************************************************************************************/
00335 
00336 BOOL PathProcessorBrush::IsAPathProcessorBrush()
00337 {
00338     return TRUE;
00339 }
00340 
00341 /********************************************************************************************
00342 
00343 >   virtual void PathProcessorBrush::ProcessPath(Path *pPath, RenderRegion *pRender);
00344 
00345     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00346     Created:    13/12/99
00347 
00348     Purpose:    Called by the RenderRegion to apply the path processing operation to 
00349                 the given path.
00350 
00351                 The PathProcessorBrush class changes the stroking (only) of paths
00352                 passed into it.
00353 
00354     Notes:      * When rendering a path, always pass in your 'this' pointer to
00355                   RenderRegion::DrawPath, so that you don't End an infinite
00356                   recursion!
00357 
00358                 * To stop rendering of the path, simply return without calling the RR
00359 
00360                 * To render this path unchanged, simply call directly back to the RR:
00361                     pRender->DrawPath(pPath, this);
00362                 
00363 ********************************************************************************************/
00364 
00365 void PathProcessorBrush::ProcessPath(Path *pPath, RenderRegion *pRender,
00366                                     PathShape ShapePath)
00367 {
00368     ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params");
00369 
00370     // We don't touch it if we're doing EOR rendering
00371     if (pRender->DrawingMode != DM_COPYPEN)
00372     {
00373         pRender->DrawPath(pPath, this);
00374         return;
00375     }
00376 
00377 
00378     // --- If the quality is set low enough, strokes are just rendered as centrelines
00379     // "low enough" is defined as the same point that Blends show their middle parts
00380     // BLOCK
00381     {
00382         QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY);
00383         if (pQuality != NULL && pQuality->QualityValue.GetBlendQuality() != Quality::FullBlend)
00384         {
00385             pRender->DrawPath(pPath, this, ShapePath);
00386             return;
00387         }
00388     }
00389 
00390 
00391 #ifdef NEWFASTBRUSHES
00392     GRenderRegionWrapper* pRendWrap = NULL;
00393     RenderRegion *pOrig = NULL;
00394     NodePath* pParentPath = NULL;
00395 
00396     if (pLinkedAttr)
00397     {
00398 TRACEUSER( "Phil", _T("PathProcessorBrush::ProcessPath:  entered with pNewAttr"));
00399         if (pLinkedAttr->GetCachedBitmap ())
00400         {
00401             // we have a bitmap, then render that ....
00402             pLinkedAttr->GetCachedBitmap ()->Render(pRender);
00403 TRACEUSER( "Phil", _T("PathProcessorBrush::ProcessPath:  rendered with bitmap\n"));
00404             return;
00405         }
00406         else
00407         {
00408             // we need to change this to be a parent of the correct type!
00409             pParentPath = (NodePath*) pLinkedAttr->GetBoundsParent ();
00410 
00411             if (pParentPath)
00412             {
00413                 // we will try and generate a bitmap (cached render) of this path ....
00414                 pRendWrap = GRenderRegionWrapper::GetAppropriateRenderWrapper ((GRenderRegion*)pRender, 1.0, pParentPath->GetBoundingRect (), 32, TRUE);
00415 TRACEUSER( "Phil", _T("PathProcessorBrush::ProcessPath:  rendered with path\n"));
00416             }
00417             else
00418             {
00419                 // since were here - somebody is probably drawing to the render region directly, so we need to
00420                 // fake that the fact that we don't have a parent
00421                 // we do this using the current clip rect of the supplied render region ...
00422                 
00423                 pRendWrap = GRenderRegionWrapper::GetAppropriateRenderWrapper ((GRenderRegion*)pRender, 1.0, pRender->GetClipRect (), 32, TRUE);
00424 TRACEUSER( "Phil", _T("PathProcessorBrush::ProcessPath:  rendered with path\n"));
00425             }
00426             // else will allow processing as normal ....
00427         }
00428     }
00429 
00430     if (pRendWrap)
00431     {
00432         pOrig = pRender;
00433         pRender = (RenderRegion*) pRendWrap->GetRenderRegion();
00434     }
00435 #endif
00436 
00437     // if we don't have a brush definition then just draw the path (our brush may have been deleted)
00438     BrushDefinition* pBrushDef = GetOurBrushDefinition();
00439     if (pBrushDef == NULL)
00440     {
00441         pRender->DrawPath(pPath, this);
00442         return;
00443     }
00444 
00445     Reset(); // sets all our members to the values they should hold at the start of the path
00446 
00447     // if we have no stroke colour then we will want to just draw the line as transparent and then leave.
00448     // If we don't then filled shapes lose their fill.  Note that we must get the strokecolour attribute
00449     // before we SaveContext.
00450     StrokeColourAttribute* pStroke = (StrokeColourAttribute*)pRender->GetCurrentAttribute(ATTR_STROKECOLOUR);
00451     BOOL NoStroke = FALSE;
00452     
00453     if (pStroke != NULL)
00454     {
00455         m_CurrentStrokeCol = pStroke->Colour;
00456         NoStroke = pStroke->Colour.IsTransparent();
00457     }
00458     else
00459     {
00460         NoStroke = TRUE;
00461     }
00462 
00463     // get the line width , if we don't exit due to no stroke colour then we will scale to this value
00464     LineWidthAttribute* pLine = (LineWidthAttribute*)pRender->GetCurrentAttribute(ATTR_LINEWIDTH);
00465     
00466     // first things: we need to draw the path in order to get any fill effect we might have, however
00467     // we don't actually want to see the path so set a transparent line colour
00468 //  ColourFillAttribute* pFill = (ColourFillAttribute*)pRender->GetCurrentAttribute(ATTR_FILLGEOMETRY);
00469 
00470     pRender->SaveContext();
00471 
00472     pRender->SetLineColour(COLOUR_TRANS);   
00473 //  pRender->SetLineWidth(500);
00474     pRender->DrawPath(pPath, this); 
00475 
00476     if (NoStroke)
00477     {
00478         pRender->RestoreContext();
00479         return;
00480     }
00481     
00482     // scale to our line width
00483     UINT32 LineWidth = pLine->LineWidth;
00484 
00485     // get the brush definition to make copies of its data for rendering
00486     if (!pBrushDef->StartRender())
00487     {
00488         TRACEUSER( "Diccon", _T("Unable to render brush%d\n"));
00489         pRender->DrawPath(pPath, this);
00490         pRender->RestoreContext();
00491         return;
00492     }
00493 
00494     UINT32 NumBrushObjects = pBrushDef->GetNumBrushObjects();
00495 
00496     // prepares caches to store transformation data
00497     if (!PrepareForRenderingLoop(NumBrushObjects))
00498     {
00499         pRender->RestoreContext();
00500         return;
00501     }
00502 
00503     // get some variables to keep track of where we are on the path
00504     double dPathLength = pPath->GetPathLength(750/2);
00505     double dOrigPathLength = dPathLength;
00506     MILLIPOINT PathLength = (MILLIPOINT)dPathLength;
00507     double PathProportion = 0.0;
00508 
00509     // this records the distance along the path at which we want to find a point
00510     MILLIPOINT DistanceToPoint = 10;
00511     
00512     // declare some locals that we need in the loop
00513     MILLIPOINT Spacing = m_BrushSpacing;
00514     
00515     CPathPointInfo PathPoint;
00516     double Angle;
00517     DocCoord Point; 
00518     BOOL ok = FALSE;
00519     BOOL Found = TRUE;
00520     UINT32 Count = 0;
00521 
00522 //TRACEUSER( "Phil", _T("Start Process Path\n"));
00523 
00524     UINT32 BrushObjectToRender = m_LastObject;
00525 
00526     
00527     // we will need to work out if each object needs to be rendered by testing its bounds
00528     // against the bounds of our render region.  This information will be used when calling
00529     // OnjectIsWithinRect
00530     DocRect RenderRect = pRender->GetClipRect();
00531     DocRect InkRect = pBrushDef->GetLargestBoundingBox();
00532     
00533     MILLIPOINT InkWidth = InkRect.Width() / 2;
00534     MILLIPOINT InkHeight = InkRect.Height() / 2;
00535     
00536     // To get our pressure data we will use either a cache that is held by our parent attribute
00537     // OR use a value function if a VariableWidthAttribute has been rendered into the render region 
00538 
00539     // get our pressure data
00540     ValueFunction* pValFunc = NULL;
00541     CDistanceSampler* pPressure = GetPressureCacheAndInitialise(pRender, &pValFunc);
00542     CSampleItem TheItem; // we need this in the loop
00543     
00544     // scale to the right line width
00545     if (LineWidth < 500)
00546         LineWidth = 500;
00547 
00548     ScaleToValue(LineWidth, !m_bValidPressure);
00549 
00550     // render a dummy variable width attribute
00551     VariableWidthAttrValue* pVarWidth = new VariableWidthAttrValue(NULL);
00552     if (pVarWidth)
00553         pRender->SetVariableWidth(pVarWidth, TRUE);
00554 
00555     // start a tiny ways in so that our first point doesn't necessarily have
00556     // a tangent of zero
00557     DistanceToPoint = 10;
00558     
00559     m_bRenderAllAttributes = TRUE;
00560 
00561     DocCoord TestPoint;
00562     
00563     if (pPath->IsClosed())
00564     {
00565         // if the path is closed then hopefully we will have adjusted the spacing so that the
00566         // path length fits an integer number of objects.  However we do not want to render
00567         // two objects on the start point so reduce the path length we actually use
00568         double ActualSpacing = m_BrushScaling * (double)m_BrushSpacing;
00569 
00570         PathLength -= (MILLIPOINT)(ActualSpacing * 0.2); // we need some margin for error
00571         dPathLength = (double)PathLength;
00572 
00573         AdjustSpacingForClosedPath(pPath, dOrigPathLength);
00574     }
00575 
00576 
00577     m_LastScalingRendered = m_BrushScaling;
00578     m_CurrentScaling = GetNextScaling(Count);
00579     // bear in mind we've now got two scaling variables at work here.  m_CurrentScaling records the actual scaling
00580     // that will be performed on our ink objects.  m_LastScaling is the scaling value compared to the starting size
00581     // of the objects.  e.g. if m_CurrentScaling = 1.5 then that means the objects will be scaled by 1.5 prior to
00582     // being rendered.  If m_LastScaling = 1.5 it means that the objects are currently 1.5 times as big as they
00583     // originally were.  I should probably rename these variables at some point.
00584 
00585     Spacing = GetNextSpacing();
00586     double TestAngle = 0;
00587     m_LastScalingRendered = m_CurrentScaling;
00588 
00589     // If we are printing or exporting then don't do the clip test
00590     BOOL bScan = pRender->IsKindOf(CC_RUNTIME_CLASS(ScanningRenderRegion))
00591                 || pRender->IsKindOf(CC_RUNTIME_CLASS(VectorFileRenderRegion));
00592 
00593     BOOL bContinue = TRUE;
00594 
00595 //::timeBeginPeriod(0);
00596 //DWORD timeStart = ::timeGetTime();
00597     while ((DistanceToPoint < PathLength) && bContinue)
00598     {
00599     //  TRACEUSER( "Diccon", _T("Count %d\n"), Count);
00600         // try and get the point 
00601         ok = GetPointAtDistance(pPath, DistanceToPoint, &Point, &Angle);
00602 
00603         // get the offset type (only important for random offset types)
00604         m_LastOffsetType = GetNextOffsetType();
00605     
00606         if (ok)  
00607         {
00608         
00609         //  TRACEUSER( "Diccon", _T("Scaling = %f\n"), m_CurrentScaling);
00610             TestPoint = AdjustPositionForOffset(Point, Angle, m_BrushScaling, GetNextOffset(), m_LastOffsetType);
00611             GetNextAngle();
00612             GetNextHueMultiplier();
00613             GetNextSaturationMultiplier();
00614 
00615             // if we're rotated then rotate the rect
00616             TestAngle = m_LastAngle;
00617             if (m_bRotate)
00618                 TestAngle += (Angle / PI * 180);  //the angle we get from GetPoint is in radians but we want degrees
00619 
00620             // is it in our render region?
00621 //TRACEUSER( "Phil", _T("Test ObjectIsWithinRect %d at %d, %d. Angle = %f\n"), Count, Point.x, Point.y, Angle);
00622             if (bScan || ObjectIsWithinRect(RenderRect, TestPoint, InkWidth, InkHeight,  m_LastScaling, TestAngle))
00623             {
00624 //TRACEUSER( "Phil", _T("Rendering Object %d at %d, %d. Angle = %f\n"), Count, Point.x, Point.y, Angle);
00625                 if (m_CurrentScaling > 0)
00626                     RenderBrushAtPoint(Point, Angle, BrushObjectToRender, Count,  pRender);
00627 
00628                 // if we've only got one object then don't keep rendering attributes that we don't have to 
00629                 if (NumBrushObjects == 1)
00630                     m_bRenderAllAttributes = FALSE;
00631 
00632             }
00633         //  else
00634             //  TRACEUSER( "Diccon", _T("NOT Rendering Object %d at %d, %d.  Angle = %f\n"), Count, Point.x, Point.y, Angle);
00635 
00636             Count++;
00637             // get the index of the next object.
00638             if (NumBrushObjects > 1)
00639             {
00640                 BrushObjectToRender = GetNextInkObject(BrushObjectToRender, NumBrushObjects);
00641             }
00642             // if the flag for this object is false then we have not rendered it yet so we need to 
00643             // get the absolute scaling value.  If we have already rendered it then we want a scaling
00644             // value relative to its last scaling.
00645             DecideWhetherToUseActualScaling(BrushObjectToRender);
00646             
00647         }
00648     
00649         // do we really want to automatically scale the spacing??? keep it for now
00650 
00651 #ifdef SCALESPACING     
00652         DistanceToPoint += (MILLIPOINT)(Spacing * m_LastScaling);
00653         
00654         if (pPressure)
00655             pPressure->SetSampleRateFromSpacing((INT32)(Spacing * m_CurrentScaling));
00656 #else
00657             DistanceToPoint += (MILLIPOINT)(Spacing * m_BrushScaling);
00658 #endif
00659         // get the next distance
00660         Spacing = GetNextSpacing();
00661 
00662         if (pValFunc != NULL)
00663         {
00664             PathProportion = (double)DistanceToPoint / dPathLength;
00665             m_CurrentPressure.m_Pressure = GetNextSampleItem(NULL, pValFunc, PathProportion).m_Pressure;
00666         
00667             // our pressure values can sometimes be erroneous
00668             if (m_CurrentPressure.m_Pressure > MAXPRESSURE)
00669                 m_CurrentPressure.m_Pressure = MAXPRESSURE;
00670         }
00671 
00672         if (pPressure != NULL)
00673         {
00674             double pLength = dOrigPathLength;       // Don't keep callnig pPath->GetPathLength(); It's complex!
00675             double pDataLength = pPressure->GetDistanceRep (), count = pPressure->GetCount ();
00676             double dataRatio = 1.0;
00677 
00678             if (pDataLength < pLength)
00679             {
00680                 dataRatio = pDataLength / pLength;
00681             }
00682             else
00683             {
00684                 dataRatio = pLength / pDataLength;
00685             }
00686 
00687             double offset = 1.0;
00688                 
00689             if (DistanceToPoint < pLength)
00690             {
00691                 offset = (DistanceToPoint / pLength) * dataRatio * count;
00692             }
00693             else
00694             {
00695                 offset = (pLength / DistanceToPoint) * dataRatio * count;
00696             }
00697             
00698             if (pPressure->GetAtPos (offset, &TheItem))//GetNext(&TheItem))
00699             {
00700                 if (TheItem.m_Pressure < MAXPRESSURE)
00701                     m_CurrentPressure.m_Pressure = TheItem.m_Pressure;
00702                 else
00703                     m_CurrentPressure.m_Pressure = MAXPRESSURE;
00704             //  TRACEUSER( "Diccon", _T("Pressure = %d\n"), TheItem.m_Pressure);
00705             }
00706         }
00707 
00708         // to get the next scaling we need to set the last scaling member to the value of the
00709         // object we are about to render next
00710         m_LastScalingRendered = m_pLastScalingRendered[BrushObjectToRender];
00711         m_CurrentScaling = GetNextScaling(Count);
00712 
00713         //TRACEUSER( "Diccon", _T("Spacing = %d, Scaling = %f\n"), Spacing, m_CurrentScaling);
00714         // this member keeps track of which side we should offset on if we have
00715         // an alternating offset
00716         if (m_AltValue == 0)
00717             m_AltValue = 1;
00718         else
00719             m_AltValue = 0;
00720         if (Found == FALSE)
00721             TRACEUSER( "Diccon", _T("Failed to find point at %d\n"), DistanceToPoint);
00722 
00723         // see if we get more rendering time
00724         bContinue = TRUE; //pView->CanContinue(pRender); 
00725     }
00726 //TRACEUSER( "Phil", _T("ProcessPath Duration = %d\n"), ::timeGetTime()-timeStart);
00727 //::timeEndPeriod(0);
00728     
00729     CleanUpAfterRender();
00730 
00731     TRACEUSER( "Diccon", _T("Finished Process Path, rendered %d objects\n"), Count);
00732     
00733     pRender->RestoreContext();
00734 
00735     pBrushDef->StopRender();
00736 
00737 #ifdef NEWFASTBRUSHES
00738     if (pRendWrap)
00739     {
00740         pRender = pOrig;
00741 
00742         KernelBitmap* kBmp = pRendWrap->GetKernelBitmap();
00743         pRendWrap->RestorePreviousRendererState();
00744 
00745         NodePath* pParentPath = (NodePath*) pLinkedAttr->GetBoundsParent ();
00746 
00747         NodeBitmap* DummyBmp = new NodeBitmap();
00748 
00749         if (DummyBmp)
00750         {       
00751             DummyBmp->SetUpPath();
00752 
00753             if (pParentPath)
00754             {
00755                 DummyBmp->CreateShape(pParentPath->GetBoundingRect ());
00756             }
00757             else
00758             {
00759                 // CGS:  since were here - somebody is probably drawing to the render region directly, so we need to
00760                 // fake that the fact that we don't have a parent
00761                 // we do this using the current clip rect of the supplied render region ...
00762                 // NOTE:  
00763 
00764                 DummyBmp->CreateShape(pRender->GetClipRect ());
00765             }
00766 
00767             DummyBmp->GetBitmapRef()->SetBitmap(kBmp);
00768             pLinkedAttr->SetCachedBitmap (DummyBmp);
00769             DummyBmp->Render (pRender);
00770         }
00771     }
00772 #endif
00773 }
00774 
00775 
00776 /********************************************************************************************
00777 
00778 >   void PathProcessorBrush::RenderBrushAtPoint(DocCoord Point, double Tangent, UINT32 BrushIndex, UINT32 Counter
00779                                                 RenderRegion* pRender, BOOL RealtimeBrush) 
00780 
00781     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00782     Created:    6/10/99
00783     Rewritten:  Phil 13/01/2004
00784     Inputs:     Point - co-ordinate where we wish to render the brush object
00785                 Angle - the tangent at that point
00786                 BrushIndex - index into the brushref array of the brush definition
00787                 Counter - the number of objects drawn so far
00788                 pBecomeA - deals with things if we are doing a DoBecomeA, can be null
00789                 RealtimeBrush - are we drawing a brush in real time (must supply a GRenderBrush region
00790                 if so) defaults to FALSE.
00791                 pRender - the render region to render on to
00792     Outputs:    -
00793     Returns:    - 
00794     Purpose:    Multipurpose !
00795                 Renders a brush object at the point specified if we supply a render region, or
00796                 calculates the bounding box of the brush at this point and adds it to our
00797                 cached rect, or makes calls PassBack for our BecomeA object.
00798 
00799                 This function is called from:
00800                 ProcessPath - for normal rendering
00801                 CalculateBoundingBox - 
00802                 DoBecomeA
00803                 OpDrawBrush::RenderStepsForTime 
00804 
00805                 Essentially what this does is:
00806 
00807                 For each Brushref
00808                     For Each Path and AttrMap belonging to the brushref
00809                         Work out render point, based on Coord provided plus offset
00810                         Scale 
00811                         Rotate
00812                         Rotate for tangent
00813                         either render, or do passback, depending on who's calling
00814                         
00815                         Reverse the transformations, however now that we are using 
00816                         copies rather than the original paths etc. we can probably
00817                         ditch these.
00818     Rewrite Notes:
00819                 The matrix handling in the original version of this routine was horribly
00820                 inefficient and resulted in compounded maths errors that caused brush facets
00821                 to "wobble" unpredictably.
00822 
00823 
00824 ********************************************************************************************/
00825 #ifdef NEW_RENDERBRUSHATPOINT
00826 void PathProcessorBrush::RenderBrushAtPoint(DocCoord Point,
00827                                             double Tangent,
00828                                             UINT32 BrushIndex,
00829                                             UINT32 Counter,
00830                                             RenderRegion* pRender,
00831                                             HandleBrushBecomeA* pBecomeA, 
00832                                             BOOL RealtimeBrush,
00833                                             BrushDefinition* pBrushDefinition)
00834 {
00835     BrushDefinition* pOurBrushDef = NULL;
00836     if (!pBrushDefinition)
00837     {
00838         pOurBrushDef = GetOurBrushDefinition();
00839     }
00840     else
00841     {
00842         pOurBrushDef = pBrushDefinition;
00843     }
00844 
00845     if (pOurBrushDef == NULL)
00846         return;
00847     
00848     // lets declare some locals here that we need in the loop later
00849     Trans2DMatrix   Trans;
00850     BrushRef*       pBrushRef; // the brushref for this brush object
00851     CCAttrMap*      pAttrMap = NULL;  // the attrmap that holds the attributes for each brush
00852     Path*           pRenderPath = NULL; // the path that we will render
00853     BlendPath*      pBlendPath = NULL;  // the source path that we have copied the render path from
00854     DocCoord*       pRenderCoords = NULL; // pointer to the coords of pRenderPath
00855     INT32           NumRenderCoords = 0; // num coords in pRenderPath
00856     DocCoord        RenderPoint; // the coord to render at
00857     MILLIPOINT      OffsetVal = 0;
00858     DocCoord        TransformCentre;
00859 
00860     BrushRef::iterator ListPosition;
00861     BlendPathOffset* pOffset = NULL; // pointer to the x,y offset of each individual object within
00862                                      // a brush made from a group
00863     
00864     // quickly ensure that we will draw a brush object
00865     if (BrushIndex >= pOurBrushDef->GetNumBrushObjects())
00866         BrushIndex = 0;
00867     
00868     // get the scaling here, this differs slightly according to whether this is a realtime
00869     // or a normal render (in the latter GetNextScaling was called in ProcessPath)
00870     double Scaling = 1.0;
00871     double ExtraAngle = 0;
00872     if (!RealtimeBrush)
00873     {
00874         Scaling = m_CurrentScaling;
00875         ExtraAngle = m_LastAngle;
00876 
00877         OffsetVal = m_LastOffset;
00878     }
00879     else
00880     {
00881         ExtraAngle = GetNextAngle();
00882         Scaling = GetNextScaling(Counter);
00883         if (Scaling <= 0)
00884             return;
00885         
00886         GetNextHueMultiplier();
00887         GetNextSaturationMultiplier();
00888 
00889         OffsetVal = GetNextOffset();
00890     }
00891     
00892     double TranspAdjust = GetNextTransparencyAdjust();
00893     double PressureTranspAdjust = GetNextPressureTranspAdjust();
00894 
00895     pBrushRef = pOurBrushDef->GetBrushRef(BrushIndex);
00896     
00897     if (pBrushRef == NULL)
00898     {
00899         ERROR3("No brushref in RenderBrushAtPoint");
00900         return;
00901     }
00902 
00903     UINT32 NumBlendPaths = pBrushRef->GetNumBlendPaths();
00904     
00905     // if we are dealing with multiple blendpaths then
00906     // a) we want to render all attributes always and
00907     // b) we want to do our tangential rotation around the point where the centre 
00908     // of the group would be
00909 //  BOOL SpecifyRotateCoord = FALSE;
00910     
00911     if (NumBlendPaths > 1)
00912     {
00913         m_bRenderAllAttributes = TRUE;
00914     }
00915 
00916     if (pBrushRef != NULL)
00917     {
00918         pOffset = pBrushRef->GetFirstOffset(&ListPosition);
00919         pBlendPath = pBrushRef->GetFirstBlendPath();
00920         pRenderPath = pBrushRef->GetFirstCopyPath();
00921 
00922         DocRect ChangedRect = DocRect(0,0,0,0);
00923     
00924         // if we're doing a passback/convert to shapes then tell it how many blendpaths we have
00925         if (pBecomeA != NULL)
00926             pBecomeA->SetNumBlendPaths(NumBlendPaths);
00927 
00928         UINT32 ObjectCounter = 0;
00929         while (pRenderPath != NULL)
00930         {
00931             DocRect BRect;
00932             Matrix transform;       // Identity
00933 
00934             // get data that we need for transformations
00935             pRenderCoords = pRenderPath->GetCoordArray();
00936             NumRenderCoords = pRenderPath->GetNumCoords();
00937 
00938             // Get the attribute map associated with the current brush path (RenderPath)
00939             pAttrMap = pBlendPath->GetCopyAttributes();
00940             if (pAttrMap == NULL)
00941             {
00942                 ERROR3("No applied attributes");
00943                 return;
00944             }
00945 
00946             ObjectCounter++;
00947 
00948             //--------------------------------------------------------------
00949             // first work out where we are going to translate to
00950             RenderPoint = AdjustPositionForOffset(Point, Tangent, m_BrushScaling, OffsetVal, m_LastOffsetType);
00951             
00952             // find out where the blendpath is at the moment
00953             BRect = pRenderPath->GetBoundingRect(); //pBlendPath->m_pPath->GetBoundingRect();
00954             DocCoord CurrentPoint = BRect.Centre();
00955         
00956             // Take relative position amongst other paths in this brush definition into account
00957             if (pOffset != NULL)
00958                 CurrentPoint = AdjustPositionForBlendPathOffset(CurrentPoint, pOffset, -1.0, Tangent);  
00959             
00960             //--------------------------------------------------------------
00961             // translate brush down to origin for scale and rotate transforms
00962             transform.translate(-CurrentPoint.x, -CurrentPoint.y );
00963     
00964             //--------------------------------------------------------------
00965             // work out the scaling matrix
00966             if (Scaling != 1.0)
00967             {
00968                 // get the scaling that we are going to use
00969                 FIXED16 NewScale(Scaling);
00970                 transform *= Matrix(NewScale, NewScale);
00971             
00972                 Trans.SetTransform(transform);
00973                 Trans.TransLines = TRUE;
00974                 
00975                 // if we're going to end up scaling the line width to zero then set a transparent stroke colour
00976                 if (pAttrMap->WillScaleLineWidthToZero(Trans))
00977                 {
00978                     AttrStrokeColour* pOldStrokeCol = NULL;
00979                     pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStrokeColour), (void*&)pOldStrokeCol );
00980                     if (pOldStrokeCol)
00981                     {
00982                         // set the transparent colour
00983                         pOldStrokeCol->Value.Colour = DocColour(COLOUR_TRANS);
00984                     }
00985                     else
00986                     {
00987                         AttrStrokeColour* pNewStrokeCol = new AttrStrokeColour;
00988                         pNewStrokeCol->Value.Colour = DocColour(COLOUR_TRANS);
00989                     }
00990                 }
00991             }
00992 
00993             //--------------------------------------------------------------
00994             // do tangential rotation 
00995             if (m_bRotate)
00996             {
00997                 // note that if we have a multiple blendpath situation then we want to rotate
00998                 // around what would be the centre point of the group.
00999                 double Tang = Tangent / PI * 180;
01000                 transform *= Matrix(Tang);
01001             }
01002         
01003             //--------------------------------------------------------------
01004             // rotate if we have to
01005             if (m_LastAngle != 0 || m_RotationMaxRand != 0)
01006             {
01007                 double RotAngle = 0;
01008                 RotAngle += m_LastAngle;
01009                 transform *= Matrix(RotAngle);
01010             }
01011         
01012             //--------------------------------------------------------------
01013             // Move into correct position on line...
01014             transform.translate(RenderPoint.x, RenderPoint.y);
01015 
01016 
01017             //--------------------------------------------------------------
01018             //--------------------------------------------------------------
01019             // Transform the path and attributes
01020             Trans.SetTransform(transform);
01021             if (Scaling != 1.0)
01022                 Trans.TransLines = TRUE;
01023 
01024             Trans.Transform(pRenderCoords, NumRenderCoords);
01025         
01026             if (m_bTile)
01027                 pAttrMap->TransformForBrush(Trans);
01028             else
01029                 pAttrMap->Transform(Trans);
01030 
01031             // scale the bounding box
01032             transform.TransformBounds(&BRect);
01033             //--------------------------------------------------------------
01034             //--------------------------------------------------------------
01035 
01036 
01037             //--------------------------------------------------------------
01038             // we now need a colour replacer, in case we are overriding colours
01039             CHSVChanger ColChanger;
01040             ColChanger.SetHueMultiplier(m_LastHueMultiplier);
01041             ColChanger.SetSaturationMultiplier(m_LastSatMultiplier);
01042             
01043             // we also want a transparency replacer
01044             CTransparencyReplacer TranspRep;
01045             TranspRep.SetAdjustmentValue(TranspAdjust);
01046             TranspRep.SetInvertedAdjuster(PressureTranspAdjust);
01047         
01048             //--------------------------------------------------------------
01049             // Finally lets draw it
01050             if (pRender != NULL)
01051             {
01052                 RenderAttributes(pRender, pAttrMap, &ColChanger, &TranspRep);
01053                 pRender->DrawPath(pRenderPath, this);
01054             }
01055 
01056             //--------------------------------------------------------------
01057             // if we're doing a passback/convert to shapes then do it here
01058             if (pBecomeA != NULL)
01059             {
01060                 AdjustFillAttributes(pAttrMap, &ColChanger, &TranspRep);
01061                 pBecomeA->Passback(pRenderPath, pAttrMap, ObjectCounter);
01062             }
01063         
01064             // we must restore any colours we replaced after drawing the path
01065             if (ColChanger.IsInitialised())
01066                 ColChanger.RestoreColours();
01067             if (TranspRep.IsInitialised())
01068                 TranspRep.RestoreTransparency();
01069             
01070             // get true bounding rect here, including the linewidth 
01071             AttrLineWidth* pLineWidth = NULL;
01072             pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrLineWidth), (void*&)pLineWidth );
01073             INT32 LineWidth = 1500;
01074             if (pLineWidth != NULL)
01075             {
01076                 LineWidth = pLineWidth->Value.LineWidth;
01077                 if (LineWidth <= 500)
01078                     LineWidth = 1500;
01079             }
01080 
01081             pRenderPath->GetTrueBoundingRect(&BRect, LineWidth, NULL);
01082             
01083             //--------------------------------------------------------------
01084             // if we have not already retrieved the last item then get it here
01085             if (ListPosition!=pBrushRef->GetEndPosition())
01086                 pOffset = pBrushRef->GetNextOffset(&ListPosition);
01087         
01088             //--------------------------------------------------------------
01089             // we need to know the on screen area that has changed
01090             if (ChangedRect.IsEmpty())
01091                 ChangedRect = BRect;
01092             else
01093                 ChangedRect = ChangedRect.Union(BRect);
01094             
01095             // if we are calculating the bounding rect then do it here using the previous calculation
01096             if (m_bCalculateRect)
01097             {
01098                 if (m_CachedRect.IsEmpty())
01099                     m_CachedRect = ChangedRect;
01100                 else
01101                     m_CachedRect = m_CachedRect.Union(ChangedRect);
01102             }
01103             
01104             //--------------------------------------------------------------
01105             // reverse the transformation of the paths and the attributes
01106             // in the brush copy by recpoying from the original BlendPath
01107             //
01108             // Reset this BrushRef Copy back to its original state before we transformed it all
01109             // Copy recopying the original data - NOT by transforming back to some equivalent state!
01110             pBlendPath->UpdateCopyPathAndAttributes();
01111 
01112             //--------------------------------------------------------------
01113             // Get next path and go round again
01114             pRenderPath = pBrushRef->GetNextCopyPath();
01115             pBlendPath = pBrushRef->GetNextBlendPath(pBlendPath);
01116 
01117         } // end while pBlendPath
01118 
01119         // if we are drawing the brush in realtime then set the changed bounding box
01120         if (RealtimeBrush == TRUE)
01121         {
01122             // oh no, another awful hack
01123 //          INT32 Height = ChangedRect.Height();
01124 //          INT32 Width = ChangedRect.Width();
01125     
01126 PORTNOTE("other","Removed GRenderBrush usage")
01127 // NB nested
01128 #ifndef EXCLUDE_FROM_XARALX
01129             ((GRenderBrush*)pRender)->SetChangedBBox(ChangedRect);
01130 #endif
01131         }
01132 
01133     } // end if pBrushRef
01134     
01135     m_pObjectRendered[BrushIndex] = TRUE;  // Set the flag to say we have rendered
01136     m_pLastScalingRendered[BrushIndex] = m_LastScaling;  // record the scaling we rendered at
01137 }
01138 #endif
01139 
01140 /********************************************************************************************
01141 
01142 >   void PathProcessorBrush::RenderBrushAtPoint(DocCoord Point, double Tangent, UINT32 BrushIndex, UINT32 Counter
01143                                                 RenderRegion* pRender, BOOL RealtimeBrush) 
01144 
01145     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01146     Created:    6/10/99
01147     Inputs:     Point - co-ordinate where we wish to render the brush object
01148                 Angle - the tangent at that point
01149                 BrushIndex - index into the brushref array of the brush definition
01150                 Counter - the number of objects drawn so far
01151                 pBecomeA - deals with things if we are doing a DoBecomeA, can be null
01152                 RealtimeBrush - are we drawing a brush in real time (must supply a GRenderBrush region
01153                 if so) defaults to FALSE.
01154                 pRender - the render region to render on to
01155     Outputs:    -
01156     Returns:    - 
01157     Purpose:    Multipurpose !
01158                 Renders a brush object at the point specified if we supply a render region, or
01159                 calculates the bounding box of the brush at this point and adds it to our
01160                 cached rect, or makes calls PassBack for our BecomeA object.
01161 
01162                 This function is called from:
01163                 ProcessPath - for normal rendering
01164                 CalculateBoundingBox - 
01165                 DoBecomeA
01166                 OpDrawBrush::RenderStepsForTime 
01167 
01168                 Essentially what this does is:
01169 
01170                 For each Brushref
01171                     For Each Path and AttrMap belonging to the brushref
01172                         Work out render point, based on Coord provided plus offset
01173                         Scale 
01174                         Rotate
01175                         Rotate for tangent
01176                         either render, or do passback, depending on who's calling
01177                         
01178                         Reverse the transformations, however now that we are using 
01179                         copies rather than the original paths etc. we can probably
01180                         ditch these.
01181 
01182 
01183 ********************************************************************************************/
01184 
01185 #ifndef NEW_RENDERBRUSHATPOINT
01186 
01187 void PathProcessorBrush::RenderBrushAtPoint(DocCoord Point, double Tangent, UINT32 BrushIndex, UINT32 Counter,
01188                                              RenderRegion* pRender, HandleBrushBecomeA* pBecomeA, 
01189                                              BOOL RealtimeBrush, BrushDefinition* pBrushDefinition)
01190 {
01191     BrushDefinition* pOurBrushDef = NULL;
01192     if (!pBrushDefinition)
01193     {
01194         pOurBrushDef = GetOurBrushDefinition();
01195     }
01196     else
01197     {
01198         pOurBrushDef = pBrushDefinition;
01199     }
01200 
01201     if (pOurBrushDef == NULL)
01202         return;
01203     
01204 //  TRACEUSER( "Diccon", _T("Brush Object = %d\n"), BrushIndex);
01205 
01206     // lets declare some locals here that we need in the loop later
01207     Trans2DMatrix Trans;
01208     Trans2DMatrix Rotate;
01209     Trans2DMatrix RevRotate;
01210     Trans2DMatrix TangMat;
01211     Trans2DMatrix RevTangent;
01212     Trans2DMatrix Scale;
01213 //  Trans2DMatrix RevScale;
01214 
01215     // allocate some locals outside  the loop
01216     BrushRef* pBrushRef; // the brushref for this brush object
01217     CCAttrMap* pAttrMap = NULL;  // the attrmap that holds the attributes for each brush
01218     Path*      pRenderPath = NULL;  // the path that we will render
01219     DocCoord*  pRenderCoords = NULL; // pointer to the coords of pRenderPath
01220     INT32      NumRenderCoords = 0; // num coords in pRenderPath
01221     DocCoord RenderPoint; // the coord to render at
01222 
01223     POSITION ListPosition;
01224     BlendPathOffset* pOffset = NULL; // pointer to the x,y offset of each individual object within
01225                                      // a brush made from a group
01226     
01227     // quickly ensure that we will draw a brush object
01228     if (BrushIndex >= pOurBrushDef->GetNumBrushObjects())
01229         BrushIndex = 0;
01230     
01231     // get the scaling here, this differs slightly according to whether this is a realtime
01232     // or a normal render (in the latter GetNextScaling was called in ProcessPath)
01233     double Scaling = 1.0;
01234     double ExtraAngle = 0;
01235     if (!RealtimeBrush)
01236     {
01237         Scaling = m_CurrentScaling;
01238         ExtraAngle = m_LastAngle;
01239     }
01240     else
01241     {
01242         ExtraAngle = GetNextAngle();
01243         Scaling = GetNextScaling(Counter);
01244         if (Scaling <= 0)
01245             return;
01246         
01247         GetNextHueMultiplier();
01248         GetNextSaturationMultiplier();
01249         
01250     }
01251     
01252     // get the offset value from the path
01253     MILLIPOINT OffsetVal = 0;
01254     if (RealtimeBrush) // || pRender == NULL)
01255         OffsetVal = GetNextOffset();
01256     else
01257         OffsetVal = m_LastOffset;
01258 
01259     double TranspAdjust = GetNextTransparencyAdjust();
01260     double PressureTranspAdjust = GetNextPressureTranspAdjust();
01261 
01262     pBrushRef = pOurBrushDef->GetBrushRef(BrushIndex);
01263     
01264     if (pBrushRef == NULL)
01265     {
01266         ERROR3("No brushref in RenderBrushAtPoint");
01267         return;
01268     }
01269     DocCoord RotateCoord;
01270     UINT32 NumBlendPaths = pBrushRef->GetNumBlendPaths();
01271     
01272     // if we are dealing with multiple blendpaths then
01273     // a) we want to render all attributes always and
01274     // b) we want to do our tangential rotation around the point where the centre 
01275     // of the group would be
01276     BOOL SpecifyRotateCoord = FALSE;
01277     
01278     if (NumBlendPaths > 1)
01279     {
01280         m_bRenderAllAttributes = TRUE;
01281         SpecifyRotateCoord = TRUE;
01282     }
01283 
01284     if (pBrushRef!= NULL)
01285     {
01286         pOffset = pBrushRef->GetFirstOffset(&ListPosition);
01287         //pBlendPath = pBrushRef->GetFirstBlendPath();
01288         pRenderPath = pBrushRef->GetFirstCopyPath();
01289 
01290         DocRect ChangedRect = DocRect(0,0,0,0);
01291         DocRect BRect;
01292     
01293         // if we're doing a passback/convert to shapes then tell it how many blendpaths we have
01294         if (pBecomeA != NULL)
01295             pBecomeA->SetNumBlendPaths(NumBlendPaths);
01296         UINT32 ObjectCounter = 0;
01297         while (pRenderPath != NULL)
01298         {   
01299             // get data that we need for transformations
01300             pRenderCoords = pRenderPath->GetCoordArray();
01301             NumRenderCoords = pRenderPath->GetNumCoords();
01302 
01303             ObjectCounter++;
01304             // first work out where we are going to translate to
01305             RenderPoint = AdjustPositionForOffset(Point, Tangent, m_BrushScaling, OffsetVal, m_LastOffsetType);
01306             
01307             // if we have a group that we want to rotate tangentially, we want the centre 
01308             // of rotation to be the original center of the group
01309             if (SpecifyRotateCoord)
01310                 RotateCoord = RenderPoint;
01311 
01312             if (pOffset != NULL)
01313                 RenderPoint = AdjustPositionForBlendPathOffset(RenderPoint, pOffset, m_LastScaling, Tangent);   
01314             
01315             // find out where the blendpath is at the moment, and transate it
01316             // to where we are now
01317             BRect = pRenderPath->GetBoundingRect(); //pBlendPath->m_pPath->GetBoundingRect();
01318             DocCoord CurrentPoint = BRect.Centre();
01319         
01320             Trans.SetTransform(RenderPoint.x  - CurrentPoint.x, RenderPoint.y - CurrentPoint.y );
01321             BRect.Translate(RenderPoint.x  - CurrentPoint.x, RenderPoint.y - CurrentPoint.y );
01322         //  TRACEUSER( "Diccon", _T("Post translate BRect hiY = %d\n"), BRect.hiy);
01323         
01324             
01325             // get the attribute map, note that attributes applying to this blendpath
01326             // are transformed by the blendpath::transform fn.
01327             pAttrMap = pBrushRef->GetCurrentAttributeCopy();            //FindAppliedAttributes(pBlendPath); // pBlendPath->FindAppliedAttributes();
01328             if (pAttrMap == NULL)
01329             {
01330                 ERROR3("No applied attributes");
01331                 return;
01332             }
01333 
01334             // Transform the path and attributes
01335             Trans.Transform(pRenderCoords, NumRenderCoords);
01336         
01337             if (m_bTile)
01338                 pAttrMap->TransformForBrush(Trans);
01339             else
01340                 pAttrMap->Transform(Trans);
01341 
01342 
01343             // get the scaling matrices
01344             Matrix ScaleMat;  
01345             Matrix RevScaleMat;
01346             
01347             // work out the scaling matrix
01348             if (Scaling != 1.0)
01349             {
01350                 // get the scaling that we are going to use
01351                 FIXED16 NewScale(Scaling);
01352                 FIXED16 OldScale = 1 / NewScale; 
01353             
01354                 // translate to origin, scale, translate back
01355                 ScaleMat*=Matrix(-BRect.Centre().x, -BRect.Centre().y);
01356                 ScaleMat*=Matrix(NewScale, NewScale);
01357                 ScaleMat*=Matrix(BRect.Centre().x, BRect.Centre().y);
01358                 
01359                 // set our 2D matrix
01360                 Scale.SetTransform(ScaleMat);
01361                 Scale.TransLines = TRUE;
01362                 
01363                 // if we're going to end up scaling the line width to zero then set a transparent stroke colour
01364                 if (pAttrMap->WillScaleLineWidthToZero(Scale))
01365                 {
01366                     AttrStrokeColour* pOldStrokeCol = NULL;
01367                     pAttrMap->Lookup((void*)CC_RUNTIME_CLASS(AttrStrokeColour), (void*&)pOldStrokeCol);
01368                     if (pOldStrokeCol)
01369                     {
01370                         // set the transparent colour
01371                         pOldStrokeCol->Value.Colour = DocColour(COLOUR_TRANS);
01372                     }
01373                     else
01374                     {
01375                         AttrStrokeColour* pNewStrokeCol = new AttrStrokeColour;
01376                         pNewStrokeCol->Value.Colour = DocColour(COLOUR_TRANS);
01377                     }
01378             
01379                 }
01380 
01381                 
01382                 // scale 'em Danno
01383                 Scale.Transform(pRenderCoords, NumRenderCoords);
01384 
01385                 // if its our first time then scale the fills to the value specified by our member
01386                 if (m_UseActualScaling)
01387                 {
01388                     if (m_BrushScaling != 0)
01389                     {
01390                         FIXED16 FillScale(m_BrushScaling);
01391                         Trans2DMatrix ScaleFills;
01392                         Matrix FillScaleMat;
01393                         FillScaleMat*=Matrix(-BRect.Centre().x, -BRect.Centre().y);
01394                         FillScaleMat*=Matrix(FillScale, FillScale);
01395                         FillScaleMat*=Matrix(BRect.Centre().x, BRect.Centre().y);
01396                         ScaleFills.SetTransform(FillScaleMat);
01397                     
01398                         pAttrMap->TransformBrushFills(ScaleFills);
01399                     }
01400 
01401                 }
01402 
01403 
01404                 if (m_bTile)
01405                     pAttrMap->TransformForBrush(Scale);
01406                 else
01407                     pAttrMap->Transform(Scale);
01408 
01409                 // scale the bounding box
01410                 ScaleMat.TransformBounds(&BRect);       
01411             }
01412 
01413             // do tangential rotation 
01414             if (m_bRotate)
01415             {
01416                 // note that if we have a multiple blendpath situation then we want to rotate
01417                 // around what would be the centre point of the group.
01418                 double Tang = Tangent / PI * 180;
01419                 if (SpecifyRotateCoord)
01420                 {
01421                     TangMat.SetTransform(RotateCoord, Tang);
01422                     RevTangent.SetTransform(RotateCoord, -Tang);
01423                     //BrushAttrValue::RotateBounds(Tang, &BRect, &RotateCoord);
01424                 }
01425                 else
01426                 {
01427                     TangMat.SetTransform(RenderPoint, Tang);
01428                     RevTangent.SetTransform(RenderPoint, -Tang);
01429                     // rotate and expand the bounding box
01430                     
01431                 }
01432                 BrushAttrValue::RotateBounds(Tang, &BRect); 
01433             
01434                 //pBlendPath->Transform(TangMat.GetpMatrix(), FALSE, m_bTile);      
01435                 TangMat.Transform(pRenderCoords, NumRenderCoords);
01436                 if (m_bTile)
01437                     pAttrMap->TransformForBrush(TangMat);
01438                 else
01439                     pAttrMap->Transform(TangMat);
01440             }
01441         
01442             
01443             //TRACEUSER( "Diccon", _T("Count = %d, Angle = %f\n"), Counter, m_LastAngle);
01444             // rotate if we have to
01445             if (m_LastAngle != 0 || m_RotationMaxRand != 0)
01446             {
01447                 double RotAngle = 0;
01448                 RotAngle += m_LastAngle;
01449                 if (SpecifyRotateCoord)
01450                     Rotate.SetTransform(RotateCoord, RotAngle);
01451                 else
01452                     Rotate.SetTransform(RenderPoint, RotAngle);
01453             
01454                 //pBlendPath->Transform(&(Rotate.GetMatrix()),FALSE, m_bTile);
01455                 Rotate.Transform(pRenderCoords, NumRenderCoords);
01456                 
01457                 if (m_bTile)
01458                     pAttrMap->TransformForBrush(Rotate);
01459                 else
01460                     pAttrMap->Transform(Rotate);
01461             
01462                 // set the reverse
01463                 RevRotate.SetTransform(RenderPoint, -RotAngle);
01464                 // rotate the bounding rect
01465                 BrushAttrValue::RotateBounds(RotAngle, &BRect);
01466             }
01467         
01468             // we now need a colour replacer, in case we are overriding colours
01469             CHSVChanger ColChanger;
01470             ColChanger.SetHueMultiplier(m_LastHueMultiplier);
01471             ColChanger.SetSaturationMultiplier(m_LastSatMultiplier);
01472             
01473             // we also want a transparency replacer
01474             CTransparencyReplacer TranspRep;
01475         
01476             TranspRep.SetAdjustmentValue(TranspAdjust);
01477             TranspRep.SetInvertedAdjuster(PressureTranspAdjust);
01478         
01479             // finally lets draw it
01480             if (pRender != NULL)
01481             {
01482                 RenderAttributes(pRender, pAttrMap, &ColChanger, &TranspRep);
01483         //      if (!RealtimeBrush)
01484                     pRender->DrawPath(pRenderPath, this);
01485         
01486             }
01487             // if we're doing a passback/convert to shapes then do it here
01488             if (pBecomeA != NULL)
01489             {
01490                 AdjustFillAttributes(pAttrMap, &ColChanger, &TranspRep);
01491                 pBecomeA->Passback(pRenderPath, pAttrMap, ObjectCounter);
01492             }
01493         
01494             // we must restore any colours we replaced after drawing the path
01495             if (ColChanger.IsInitialised())
01496                 ColChanger.RestoreColours();
01497             if (TranspRep.IsInitialised())
01498                 TranspRep.RestoreTransparency();
01499             
01500             // get true bounding rect here, including the linewidth 
01501             AttrLineWidth* pLineWidth = NULL;
01502             pAttrMap->Lookup((void*)CC_RUNTIME_CLASS(AttrLineWidth), (void*&)pLineWidth);
01503             INT32 LineWidth = 1500;
01504             if (pLineWidth != NULL)
01505             {
01506                 LineWidth = pLineWidth->Value.LineWidth;
01507                 if (LineWidth <= 500)
01508                     LineWidth = 1500;
01509             }
01510 
01511             //pBlendPath->m_pPath->GetTrueBoundingRect(&BRect, LineWidth, pAttrMap);
01512             pRenderPath->GetTrueBoundingRect(&BRect, LineWidth, NULL);
01513             
01514             // reverse the rotation
01515             if (m_LastAngle != 0 )
01516             {
01517             //  pBlendPath->Transform(RevRotate.GetpMatrix(), FALSE, m_bTile);
01518                 RevRotate.Transform(pRenderCoords, NumRenderCoords);
01519                 if (m_bTile)
01520                     pAttrMap->TransformForBrush(RevRotate);
01521                 else
01522                     pAttrMap->Transform(RevRotate);
01523                 DocRect NewRect = BRect;
01524                 BrushAttrValue::RotateBounds(m_LastAngle, &NewRect);
01525                 BRect = BRect.Union(NewRect);
01526             }
01527             // reverse the tangential rotation
01528             if (m_bRotate )
01529             {
01530                 //pBlendPath->Transform(RevTangent.GetpMatrix(), FALSE, m_bTile);
01531                 RevTangent.Transform(pRenderCoords, NumRenderCoords);
01532                 if (m_bTile)
01533                     pAttrMap->TransformForBrush(RevTangent);
01534                 else
01535                     pAttrMap->Transform(RevTangent);
01536 
01537                 DocRect NewRect = BRect;
01538                 BrushAttrValue::RotateBounds(Tangent, &NewRect);
01539                 BRect = BRect.Union(NewRect);
01540             }
01541             //TRACEUSER( "Diccon", _T("Rendering Object %d at %d, %d\n"), m_BrushStep, Point.x, Point.y);
01542                 
01543             // if we have not already retrieved the last item then get it here
01544             if (ListPosition != NULL)
01545                 pOffset = pBrushRef->GetNextOffset(&ListPosition);
01546         
01547             pRenderPath = pBrushRef->GetNextCopyPath();
01548 
01549             //pBlendPath = pBrushRef->GetNextBlendPath(pBlendPath);
01550                     
01551             // we need to know the on screen area that has changed
01552             if (ChangedRect.IsEmpty())
01553                 ChangedRect = BRect;
01554             else
01555                 ChangedRect = ChangedRect.Union(BRect);
01556             
01557             // if we are calculating the bounding rect then do it here using the previous calculation
01558             if (m_bCalculateRect)
01559             {
01560                 if (m_CachedRect.IsEmpty())
01561                     m_CachedRect = ChangedRect;
01562                 else
01563                     m_CachedRect = m_CachedRect.Union(ChangedRect);
01564             }
01565             
01566         } // end while pBlendPath
01567         
01568         // if we are drawing the brush in realtime then set the changed bounding box
01569         if (RealtimeBrush == TRUE)
01570         {
01571             // oh no, another awful hack
01572             INT32 Height = ChangedRect.Height();
01573             INT32 Width = ChangedRect.Width();
01574         //  if (NumBlendPaths > 1)
01575         //  ChangedRect.Inflate((INT32)(Height * 1.25), (INT32)(Width *1.25));
01576     
01577             ((GRenderBrush*)pRender)->SetChangedBBox(ChangedRect);
01578         }
01579 
01580     } // end if pBrushRef
01581     
01582     m_pObjectRendered[BrushIndex] = TRUE;  // Set the flag to say we have rendered
01583     m_pLastScalingRendered[BrushIndex] = m_LastScaling;  // record the scaling we rendered at
01584 
01585 }
01586 #endif
01587 
01588 
01589 /********************************************************************************************
01590 
01591 >void PathProcessorBrush::RenderAttributes(RenderRegion* pRender, CCAttrMap* pAttrMap, 
01592                                           CHSVChanger* pReplacer, CTransparencyReplacer* pTranspRep)
01593 
01594     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01595     Created:    6/10/99
01596     Inputs:     pRender = ptr to render region
01597                 pAttrMap - the attribute map to render
01598                 pColChange - object that changes the colours in our fills
01599                 pTranspRep - object to change transparencies
01600     Outputs:    -
01601     Returns:    -
01602     Purpose:    Renders the attributes to the given render region.  This function has ended up being
01603                 really messy because people have insisted on being able to override various of the
01604                 cached attributes.  Heres a brief rundown:
01605                 - m_bUseLocalFillColour means that we use to fill colour closest to our attribute
01606                 node instead of the cached fill colour. Note that if m_bUseLocalFillColour is FALSE
01607                 we may still use the local fill colour instead of our Named colours.
01608                 - Instead of our cached transparency we may choose not to render transparency, thereby
01609                 letting the previously rendered transparency apply to our brush objects.
01610 
01611                 Prior to rendering our attribute map we must render a blank transparency attribute.
01612                 This is because we are unable to call RestoreContext from a path processor and if
01613                 a previous blendpath rendered a transparency we do not want it to remain.  This
01614                 also applies to fill colour.
01615 
01616     SeeAlso:    -
01617 
01618 ********************************************************************************************/
01619 
01620 void PathProcessorBrush::RenderAttributes(RenderRegion* pRender, CCAttrMap* pAttrMap, 
01621                                           CHSVChanger* pColChange, CTransparencyReplacer* pTranspRep)
01622 {
01623     // Check entry params
01624     BOOL ok = (pRender != NULL && pAttrMap != NULL);
01625     ERROR3IF(!ok,"One or more NULL entry params");
01626     if (!ok) return;
01627 
01628     BOOL bRenderedTransp = FALSE;
01629     BOOL bRenderedColourFill = FALSE;
01630 
01631     CCRuntimeClass     *pType;
01632     void               *pVal;
01633     NodeAttribute      *pNodeAttr;
01634     
01635     m_bRenderAllAttributes = TRUE; // now that we always need to have rendered transparencies we must force this on
01636 
01637     pRender->SetFillColour(COLOUR_NONE);// clear any previous fill colours
01638 
01639     // iterating all (key, value) pairs
01640     for( CCAttrMap::iterator Pos = pAttrMap->GetStartPosition(); Pos != pAttrMap->GetEndPosition(); )
01641     {
01642         // Get attr at position Pos 
01643         pAttrMap->GetNextAssoc( Pos, pType, pVal );
01644 
01645         // pVal is actually an attribute, so get a ptr to it and render it
01646         pNodeAttr = (NodeAttribute *)pVal;
01647 
01648         // if its a fill we might prefer to use the local stroke colour instead
01649         if (pNodeAttr->IsAColourFill() && !pNodeAttr->IsATranspFill() && !pNodeAttr->IsABitmapFill())    
01650         {
01651             
01652             // as we now have to deal with named colours this is a bit complex but basically:
01653             // - if m_bUseLocalFillColour == FALSE, && m_bUseNamedColours == FALSE && this fill has
01654             // a named colour, then we will end up rendering the local colour anyway.  Otherwise we
01655             // will render this colour normally.
01656             // Another case to cater for, if we have hue and saturation variations then we need to do those also
01657             
01658             bRenderedColourFill = TRUE;
01659             if (!m_bUseLocalFillColour)
01660             {
01661                 
01662                 //first find out if we have a named colour
01663                 ColourFillAttribute* pVal = (ColourFillAttribute*)pNodeAttr->GetAttributeValue();
01664                 if (pVal->ContainsNamedColour())
01665                 {
01666                     if (!m_bUseNamedColours)
01667                     {
01668                         //TRACEUSER( "Diccon", _T("Overriding Named Colours\n"));
01669                         // we need to initialise the Replacer with our attribute and the local
01670                         // stroke colour
01671                 
01672                         DocColour Col = m_CurrentStrokeCol;
01673                         pColChange->Initialise(pVal, &Col); 
01674                         pColChange->ReplaceColours();
01675 
01676                         // note that CNamedColorReplacer::RestoreColours() MUST be called AFTER 
01677                         // DrawPaths in the render routine, if it is not the the colours are permanently replaced.
01678                     }
01679                 }
01680 
01681                 // change HSV values if we need to
01682                 if (pColChange->ShouldChangeHSV())
01683                 {
01684                     pColChange->SetColourFill(pVal);
01685                     pColChange->ChangeHSVValues();
01686                 }
01687             
01688                 // check to see if we actually need to render it
01689                 if (m_bRenderAllAttributes || pNodeAttr->NeedsToRenderAtEachBrushStroke())
01690                 {
01691                     pNodeAttr->Render(pRender);
01692                 }
01693 
01694             }
01695             else
01696             {
01697                 // we want the local colour
01698                 if (m_pParentAttr != NULL)
01699                 {
01700                     DocColour LocalColour = m_CurrentStrokeCol;
01701                     if (pColChange != NULL)
01702                     {
01703                         pColChange->ChangeColour(&LocalColour);
01704                     }
01705                     pRender->SetFillColour(LocalColour);
01706                 }
01707             }
01708         }
01709         else if (pNodeAttr->IsATranspFill())
01710         {
01711             AdjustAndRenderTransparency(pRender, (AttrFillGeometry*)pNodeAttr, pTranspRep);
01712             bRenderedTransp = TRUE;
01713         }
01714         else
01715         {
01716         
01717             if (m_bRenderAllAttributes || pNodeAttr->NeedsToRenderAtEachBrushStroke())
01718             {
01719                 pNodeAttr->Render(pRender);
01720             }
01721         }
01722     
01723     }
01724     
01725 
01726     if (m_bRenderAllAttributes)
01727     {
01728         // as we can't restore contexts and we have not already rendered a transparency then 
01729         //we must render a blank transparency, in case we have a transpareny left over from the last object
01730         if (m_pDefaultTransp != NULL && !bRenderedTransp)
01731         {
01732             AdjustAndRenderTransparency(pRender, m_pDefaultTransp, pTranspRep);
01733             m_pDefaultTransp->Render(pRender);
01734         }
01735     }
01736 
01737     if (bRenderedColourFill == FALSE)
01738         pRender->SetFillColour(COLOUR_NONE);
01739 
01740     // ensure that if we are tiling then our fill mapping type is not single
01741     if (m_bTile)
01742     {
01743         FillMappingAttribute* pVal = (FillMappingAttribute*)pRender->GetCurrentAttribute(ATTR_FILLMAPPING);
01744         if (pVal)
01745         {
01746             if (pVal->Repeat == RT_Simple)
01747             {
01748                 // Whose dozy idea was this?  This directly alters the FillMapping attribute
01749                 // applied to the object with the brush-stroked outline.
01750                 // pVal->Repeat = RT_Repeating;
01751 
01752                 // Instead we will create a copy of the current attribute, set it's Repeat
01753                 // value to "repeating" and render it.
01754                 FillMappingAttribute* pNewVal = (FillMappingAttribute*)(pVal->GetRuntimeClass()->CreateObject());
01755                 if (pNewVal)
01756                 {
01757                     pNewVal->SimpleCopy(pVal);
01758                     pNewVal->Repeat = RT_Repeating;
01759                     pRender->SetFillMapping(pNewVal, TRUE);
01760                 }
01761             }
01762         }
01763     }
01764 }
01765 
01766 
01767 /********************************************************************************************
01768 
01769 >void PathProcessorBrush::AdjustAndRenderTransparency(RenderRegion* pRender, AttrFillGeometry* pAttrTransp, 
01770                                                      CTransparencyReplacer* pRep)
01771     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01772     Created:    6/10/99
01773     Inputs:     pRender = ptr to render region
01774                 pAttrTransp - the attribute to render, this must be a transparency attribute
01775                 pRep - the replacer which changes transparency values
01776     Outputs:    pAttrTransp gets its values changed
01777     Returns:    -
01778     Purpose:    To adjust the transparency attribute with the replacer and then render it into
01779                 the render region.  Note that you must call CTransparencyReplacer::Restore() after
01780                 you have rendered your objects with this transparency, otherwise the change will
01781                 be permanent
01782     SeeAlso:    -
01783 
01784 ********************************************************************************************/
01785 
01786 void PathProcessorBrush::AdjustAndRenderTransparency(RenderRegion* pRender, AttrFillGeometry* pAttrTransp, 
01787                                                      CTransparencyReplacer* pRep)
01788 {
01789     if (pRender == NULL || pAttrTransp == NULL || pRep == NULL)
01790         return;
01791 
01792     if (!pAttrTransp->IsATranspFill())
01793     {       
01794         ERROR3("Attribute is not transparent in PathProcessorBrush::AdjustAndRenderTransparency");
01795         return;
01796     }
01797 
01798     TranspFillAttribute* pTranspVal = (TranspFillAttribute*)pAttrTransp->GetAttributeValue();
01799     if (pTranspVal != NULL)
01800     {
01801         // see if our parent attr has a local transparency value, if so we will use that
01802         if (m_pParentAttr != NULL)
01803         {
01804             UINT32 ReplaceVal = m_pParentAttr->GetLocalTranspValue();
01805             if (ReplaceVal > 0)
01806                 pRep->SetReplacementValue((INT32)ReplaceVal);
01807             UINT32 Type = m_pParentAttr->GetLocalTranspType();
01808             pTranspVal->SetTranspType(Type);
01809         }
01810         pRep->SetTransparencyAttr(pTranspVal);
01811         pRep->ReplaceTransparency();
01812     }
01813 
01814     pAttrTransp->Render(pRender);
01815 }
01816 
01817 
01818 /********************************************************************************************
01819 
01820 >void PathProcessorBrush::AdjustFillAttributes(CCAttrMap* pAttrMap, CHSVChanger* pReplacer, 
01821                                               CTransparencyReplacer* pTransRep)
01822     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01823     Created:    6/10/99
01824     Inputs:     pAttrMap - the map containing attributes for this brush
01825                 pColChange - object to replace HSV values for colour fills
01826                 pTranspRep - object to replace transparency values
01827     Outputs:    
01828     Returns:    -
01829     Purpose:    To adjust the colour fill and transparency values in the attribute map
01830                 Note that you must call the Restore() method for the two replacer objects
01831                 otherwise the attributes will be permanently changed
01832                 
01833     SeeAlso:    -
01834 
01835 ********************************************************************************************/
01836 
01837 void PathProcessorBrush::AdjustFillAttributes(CCAttrMap* pAttrMap, CHSVChanger* pColChange, 
01838                                               CTransparencyReplacer* pTranspRep)
01839 {
01840     if (pAttrMap == NULL || pColChange == NULL || pTranspRep == NULL)
01841     {
01842         ERROR3("Invalid inputs to PathProcessorBrush::AdjustFillAttributes");
01843         return;
01844     }
01845 
01846 
01847     // lets find our attributes
01848     CCRuntimeClass     *pType;
01849     void               *pVal;
01850     NodeAttribute      *pNodeAttr;
01851     
01852     BOOL FoundTransp = FALSE;
01853 
01854     // iterating all (key, value) pairs
01855     for( CCAttrMap::iterator Pos = pAttrMap->GetStartPosition(); Pos != pAttrMap->GetEndPosition(); )
01856     {
01857         // Get attr at position Pos
01858         pAttrMap->GetNextAssoc(Pos,pType,pVal);
01859 
01860         // pVal is actually an attribute, so get a ptr to it and render it
01861         pNodeAttr = (NodeAttribute *)pVal;
01862 
01863         if (pNodeAttr->IsAColourFill())
01864         {
01865             if (!m_bUseLocalFillColour)
01866             {
01867                 
01868                 //first find out if we have a named colour
01869                 ColourFillAttribute* pVal = (ColourFillAttribute*)pNodeAttr->GetAttributeValue();
01870                 if (pVal->ContainsNamedColour())
01871                 {
01872                     if (!m_bUseNamedColours)
01873                     {
01874                         // we need to initialise the Replacer with our attribute and the local
01875                         // stroke colour
01876                         if (m_pParentAttr != NULL && pColChange != NULL)
01877                         {
01878                             DocColour Col = m_CurrentStrokeCol;
01879                             pColChange->Initialise(pVal, &Col);
01880                             pColChange->ReplaceColours();
01881 
01882                         }
01883                         // note that CNamedColorReplacer::RestoreColours() MUST be called AFTER 
01884                         // DrawPaths in the render routine, if it is not the the colours are permanently replaced.
01885                     }
01886                 }
01887 
01888                 // change HSV values if we need to
01889                 if (pColChange->ShouldChangeHSV())
01890                 {
01891                     pColChange->SetColourFill(pVal);
01892                     pColChange->ChangeHSVValues();
01893                 }
01894 
01895             }
01896         
01897         }
01898         if (pNodeAttr->IsATranspFill())
01899         {
01900             TranspFillAttribute* pTranspVal = (TranspFillAttribute*)pNodeAttr->GetAttributeValue();
01901             if (pTranspVal != NULL)
01902             {
01903                 // see if our parent attr has a local transparency value, if so we will use that
01904                 if (m_pParentAttr != NULL)
01905                 {
01906                     UINT32 ReplaceVal = m_pParentAttr->GetLocalTranspValue();       
01907                     if (ReplaceVal > 0)
01908                     {
01909                         pTranspRep->SetReplacementValue((INT32)ReplaceVal);
01910                         UINT32 Type = m_pParentAttr->GetLocalTranspType();
01911                         pTranspVal->SetTranspType(Type);
01912                     }
01913 
01914                 }
01915                 
01916                 pTranspRep->SetTransparencyAttr(pTranspVal);
01917                 pTranspRep->ReplaceTransparency();
01918                 FoundTransp = TRUE;
01919             }
01920         }
01921         
01922     }
01923     
01924     // if we didn't find a transparency attribute then we might have to make one
01925     if (FoundTransp == FALSE)
01926     {
01927         AttrFlatTranspFill* pTransp = new AttrFlatTranspFill;
01928         if (m_pParentAttr != NULL && pTransp != NULL)
01929         {
01930             // get the transparency value of our parent
01931             UINT32 TranspVal = m_pParentAttr->GetLocalTranspValue();        
01932             TranspFillAttribute* pTranspVal = (TranspFillAttribute*)pTransp->GetAttributeValue();
01933             pTranspVal->Transp = TranspVal;
01934             
01935             UINT32 Type = m_pParentAttr->GetLocalTranspType();
01936             pTranspVal->SetTranspType(Type);
01937 
01938             // add it to the map
01939             pAttrMap->SetAt( CC_RUNTIME_CLASS(AttrFlatTranspFill), (void*)pTransp );
01940 
01941             // now do the replacing
01942             pTranspRep->SetTransparencyAttr(pTranspVal);
01943             pTranspRep->ReplaceTransparency();
01944 
01945         }
01946 
01947     }
01948 }
01949 
01950 
01951 /********************************************************************************************
01952 
01953 >   DocCoord PathProcessorBrush::AdjustPositionForOffset(DocCoord OriginalPoint, BlendPathOffset Offset) 
01954 
01955     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01956     Created:    6/10/99
01957     Inputs:     OriginalPoint - the point on the line at the correct distance for us to draw an object
01958                 Angle - the tangent at this point on the path
01959                 Scaling - the scaling to use
01960                 Offset - the blendpathoffset for this blendpath
01961                 OffsetType - used only for random offset types, this can be left right or centre and
01962                 is determined by GetNextOffsetType
01963     Outputs:    -
01964     Returns:    the new position where we wish the object to be drawn 
01965     Purpose:    To determine where the next brush object should be drawn.  The position from the
01966                 line can be altered by the following factors;
01967                 
01968             
01969 
01970                 - m_PathOffsetType and m_PathOffsetValue:  These translations map the point on one side of
01971                 the path or the other, the value determines exactly how far from the path they will be.
01972 
01973                 - m_PositionRandomness:  introduces a random element to the position of the object
01974     SeeAlso:    -
01975 
01976 *********************************************************************************************************/
01977 
01978 DocCoord PathProcessorBrush::AdjustPositionForOffset(DocCoord OriginalPoint, double Angle, double Scaling, 
01979                                                      MILLIPOINT OffsetValue, UINT32 OffsetType)
01980                                              //BlendPathOffset* pOffset)
01981 {   
01982     // if its zero or less we don't want to know
01983     if (OffsetValue <= 0)
01984         return OriginalPoint;
01985 
01986     // scale it to our current scaling
01987     OffsetValue = (MILLIPOINT)((double) OffsetValue * Scaling);
01988 //  TRACEUSER( "Diccon", _T("OffsetVal = %d\n"), OffsetValue);
01989     double theta;
01990     double NewX;
01991     double NewY;
01992 
01993     
01994     switch (m_PathOffsetType)
01995     {
01996         case OFFSET_NONE:
01997             break;
01998         case OFFSET_ALTERNATE:
01999             if (m_AltValue == 0)
02000             {
02001                 theta = Angle - (PI / 2);               
02002             }
02003             else
02004             {
02005                 theta = Angle + (PI / 2);
02006             }
02007             
02008             NewX = OffsetValue * cos (theta);
02009             NewY = OffsetValue * sin (theta);
02010         //  TRACEUSER( "Diccon", _T("Y Offset = %d\n"), (INT32)NewY);
02011             OriginalPoint.translate((INT32)NewX, (INT32)NewY);
02012             break;
02013         case OFFSET_RIGHT:
02014             theta = Angle - (PI / 2);
02015             NewX = OffsetValue * cos (theta);
02016             NewY = OffsetValue * sin (theta);
02017             OriginalPoint.translate((INT32)NewX, (INT32)NewY);
02018             break;
02019         case OFFSET_LEFT:
02020             theta = Angle + (PI / 2);
02021             NewX = OffsetValue * cos (theta);
02022             NewY = OffsetValue * sin (theta);
02023             OriginalPoint.translate((INT32)NewX, (INT32)NewY);
02024             break;
02025         case OFFSET_RANDOM: 
02026         {
02027         //  TRACEUSER( "Diccon", _T("Offset type = %d\n"), OffsetType);
02028             switch (OffsetType)
02029             {
02030                 case OFFSETTYPE_LEFT:
02031                     theta = Angle + (PI / 2);
02032                     NewX = OffsetValue * cos (theta);
02033                     NewY = OffsetValue * sin (theta);
02034                     OriginalPoint.translate((INT32)NewX, (INT32)NewY);
02035                     break;
02036                 case OFFSETTYPE_RIGHT:
02037                     theta = Angle - (PI / 2);
02038                     NewX = OffsetValue * cos (theta);
02039                     NewY = OffsetValue * sin (theta);
02040                     OriginalPoint.translate((INT32)NewX, (INT32)NewY);
02041                     break;
02042                 case OFFSETTYPE_CENTRE:
02043                     break;
02044                 default:
02045                     ERROR3("Invalid offset type returned");
02046                     break;
02047             }
02048             break;
02049         }
02050             
02051         default:
02052             ERROR3("Unknown offset type");
02053             break;
02054     }
02055 
02056     return OriginalPoint;
02057 }
02058 
02059 /********************************************************************************************
02060 
02061 >   DocCoord PathProcessorBrush::AdjustPositionForBlendPathOffset(DocCoord OriginalPoint, BlendPathOffset* pOffset) 
02062 
02063     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02064     Created:    6/10/99
02065     Inputs:     OriginalPoint - the point on the line at the correct distance for us to draw an object
02066                 Offset - the blendpathoffset for this blendpath
02067                 Scaling
02068                 Angle
02069     Outputs:    -
02070     Returns:    the new position where we wish the object to be drawn 
02071     Purpose:    To determine where the next brush object should be drawn.  The position from the
02072                 line can be altered by the following factors;
02073                 
02074     SeeAlso:    -
02075 
02076 *********************************************************************************************************/
02077 
02078 DocCoord PathProcessorBrush::AdjustPositionForBlendPathOffset(DocCoord OriginalPoint, BlendPathOffset* pOffset, 
02079                                                             double Scaling, double Angle)
02080 {
02081     if (pOffset->m_XOffset == 0 && pOffset->m_YOffset == 0)
02082         return OriginalPoint;
02083 
02084     MILLIPOINT XOffset;
02085     MILLIPOINT YOffset;
02086 
02087     DocCoord RotateCentre = OriginalPoint;
02088 
02089     XOffset = (MILLIPOINT)(pOffset->m_XOffset *Scaling);
02090     YOffset = (MILLIPOINT)(pOffset->m_YOffset *Scaling);
02091 
02092     // not much to it really
02093     OriginalPoint.translate(XOffset, YOffset);
02094 
02095     return OriginalPoint;
02096 }
02097 
02098 
02099 /********************************************************************************************
02100 >   void PathProcessorBrush::RenderTimeStampPoints(RenderRegion* pRender)
02101 
02102     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02103     Created:    30/4/99
02104     Inputs:     pRender - the region to render into
02105                 
02106     Outputs:    
02107             
02108     Returns:    TRUE/FALSE for success/failure
02109     Purpose:    Accesses the timestamp cache of the parent attribute and tests its points
02110                 against the bounds of the render region, rendering them if they are inside.
02111             
02112 ********************************************************************************************/
02113 
02114 void PathProcessorBrush::RenderTimeStampPoints(RenderRegion* pRender)
02115 {
02116     if (m_pParentAttr == NULL)
02117     {
02118         //ERROR3("Parent attribute is null");
02119         return;
02120     }
02121 
02122     BrushDefinition* pBrushDef = GetOurBrushDefinition();
02123     if (pBrushDef == NULL)
02124     {
02125         ERROR3("No brush definition");
02126         return;
02127     }
02128 
02129     UINT32 NumBrushObjects = pBrushDef->GetNumBrushObjects();
02130     
02131     Reset();
02132         
02133     // declare some locals that we need in the loop
02134 //  BOOL ok = FALSE;
02135 //  BOOL Found = TRUE;
02136     UINT32 Count = 0;
02137     UINT32 BrushObjectToRender = 0;
02138     
02139     DocRect InkRect = pBrushDef->GetLargestBoundingBox();
02140     DocRect RenderRect = pRender->GetClipRect();
02141 
02142     // if we're rotated then rotate the rect, don't have time to work out
02143     // the exact angle so use 90 deg, which gives the largest increase in size
02144     if ((m_bRotate) || (m_RotateAngle != 0.0) || m_RotationMaxRand != 0)
02145         m_pParentAttr->RotateBounds(90, &InkRect);
02146 
02147     MILLIPOINT InkWidth = InkRect.Width() / 2;
02148     MILLIPOINT InkHeight = InkRect.Height() / 2;
02149     
02150     // get the list from our attribvute
02151     TimeStampList* pTimeStampList = m_pParentAttr->GetTimeStampList();
02152     if( pTimeStampList == NULL || pTimeStampList->empty() )
02153     {
02154         ERROR3("No Timestamp list");
02155         return;
02156     }
02157     TimeStampList::iterator ListPos = pTimeStampList->begin();
02158     TimeStampBrushPoint TSBP;
02159 //  PressureList* pPressure = m_pParentAttr->GetPressureCache();
02160 //  POSITION PressurePos;
02161 //  if (pPressure)
02162 //      PressurePos = pPressure->GetHeadPosition();
02163     m_bRenderAllAttributes = TRUE;
02164     DocCoord TestPoint;
02165     m_bRenderAllAttributes = TRUE;
02166     while( ListPos != pTimeStampList->end() )
02167     {
02168         TSBP = *ListPos++;
02169         
02170         m_CurrentScaling = GetNextScaling(Count);
02171 //      if (pPressure != NULL)
02172 //      {
02173 //          if (PressurePos != NULL)
02174 //              m_CurrentPressure = 127; //pPressure->GetNext(PressurePos);
02175 //      }
02176         // get the offset type (only important for random offset types)
02177         SetNextOffsetType();
02178         GetNextAngle();
02179         TestPoint = AdjustPositionForOffset(TSBP.m_Point, TSBP.m_Tangent,  m_CurrentScaling, GetNextOffset(), m_LastOffsetType);
02180         // is it in our render region?
02181         if (ObjectIsWithinRect(RenderRect, TestPoint, InkWidth, InkHeight, m_CurrentScaling))
02182         {
02183     //      TRACEUSER( "Diccon", _T("Rendering Object\n"));
02184             RenderBrushAtPoint(TSBP.m_Point, TSBP.m_Tangent,
02185                        BrushObjectToRender, Count,  pRender);
02186             
02187         }
02188         if (NumBrushObjects > 1)
02189                 BrushObjectToRender = GetNextInkObject(BrushObjectToRender, NumBrushObjects);
02190         Count++;
02191         GetNextAngle();
02192         // this member keeps track of which side we should offset on if we have
02193         // an alternating offset
02194         if (m_AltValue == 0)
02195             m_AltValue = 1;
02196         else
02197             m_AltValue = 0;
02198 
02199     }
02200     pRender->RestoreContext();
02201 //  TRACEUSER( "Diccon", _T("Rendered %d Objects\n"), Count);
02202 }
02203 
02204 
02205 
02206 
02207 /********************************************************************************************
02208 
02209 >   BOOL PathProcessorBrush::ObjectIsWithinRect(DocRect Rect, DocCoord Centre, 
02210                                                 MILLIPOINT HalfWidth, MILLIPOINT HalfHeight,
02211                                                 double Scaling)
02212 
02213     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02214     Created:    13/12/99
02215     Inputs:     Rect -  rect to test against
02216                 Centre - the centre of the object to test
02217                 HalfWidth - half the width of the object bounding rect
02218                 HalfHeight - half the height;
02219                 Scaling - the scaling
02220                 Angle - the angle at which this object is rotated IN DEGREES
02221     Returns:    TRUE, if any part of this object intersects the rect.
02222 
02223     Purpose:    as above
02224 ********************************************************************************************/
02225 
02226 BOOL PathProcessorBrush::ObjectIsWithinRect(DocRect Rect, DocCoord Centre, MILLIPOINT HalfWidth,
02227                                             MILLIPOINT HalfHeight, double Scaling, double Angle)
02228 {
02229     if (Rect.IsEmpty())
02230         return FALSE;
02231 
02232     // if we're scaling then adjust the object widths
02233     if (Scaling != 1.0)
02234     {
02235         if (Scaling <=0)
02236             return FALSE;
02237         HalfHeight = (MILLIPOINT)((double)HalfHeight * Scaling);
02238         HalfWidth = (MILLIPOINT)((double)HalfWidth * Scaling);
02239     }
02240     
02241     
02242     DocRect TestRect;
02243     TestRect.hi.x = Centre.x + HalfWidth;
02244     TestRect.lo.x = Centre.x - HalfWidth;
02245     TestRect.hi.y = Centre.y + HalfHeight;
02246     TestRect.lo.y = Centre.y - HalfHeight;
02247 
02248     BrushAttrValue::RotateBounds(Angle, &TestRect, &Centre);
02249 
02250     
02251     if (Rect.IsIntersectedWith(TestRect))
02252     {
02253         //TRACEUSER( "Diccon", _T("Rects intersect\n"));
02254         return TRUE;
02255     }
02256 
02257     return FALSE;
02258 }
02259 
02260 
02261 /********************************************************************************************
02262 >   BOOL PathProcessorBrush::GetPointAtDistance(Path* pPath, MILLIPOINT Distance, DocCoord* pPoint, 
02263                                                 double* pTangent)
02264 
02265     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02266     Created:    30/4/99
02267     Inputs:     pPath - the path along which is the poiht we want
02268                 Distance = a length along the path
02269     Outputs:    pPoint = the coordinate of the point that distance along the path
02270                 pTangent = tangent at this point (can be NULL)
02271             
02272     Returns:    TRUE/FALSE for success/failure
02273     Purpose:    Gets the coordinate of a point a certain distance along this path, either by looking
02274                 in its cache pr by calling the Path class function
02275             
02276 ********************************************************************************************/
02277 
02278 BOOL PathProcessorBrush::GetPointAtDistance(Path* pPath, MILLIPOINT Distance, DocCoord* pPoint, 
02279                                                 double* pTangent)                                      
02280 {
02281     ERROR2IF(pPoint == NULL,FALSE,"NULL pPoint param");
02282     ERROR2IF(pPath == NULL, FALSE, "Path is NULL");
02283 //  ERROR2IF(m_pParentAttr == NULL, FALSE, "parent attribute is NULL");
02284     BOOL Found = FALSE;
02285     BrushPointInfo PointInfo;
02286 
02287 
02288 #ifdef BRUSHPOINTSCACHE
02289     // retrieve pointer to the cache from parent attribute
02290     PointsMap* pCache = NULL;
02291     if (m_pParentAttr != NULL && m_pParentAttr->CanUsePointsCache())
02292     {
02293         pCache = m_pParentAttr->GetCache();
02294         if (pCache != NULL)
02295         {
02296             // look for point in the cache
02297             PointsMap::iterator iter = pCache->find( Distance );
02298             Found = ( pCache->end() != iter );
02299             if( Found )
02300             {
02301                 PointInfo = iter->second;
02302             }
02303 
02304         //  if (Found)
02305         //      TRACEUSER( "Diccon", _T("Point found in cache %d, %d\n"), PointInfo.m_Point.x, PointInfo.m_Point.y);
02306         }
02307     }
02308     
02309 #endif
02310     if (!Found)
02311     {   
02312         // get the point from the path
02313         if (pPath->GetPointAtDistance(Distance,&PointInfo.m_Point,&PointInfo.m_Tangent, &PointInfo.m_Pressure))
02314         {
02315 #ifdef BRUSHPOINTSCACHE
02316             // insert it into the cache
02317             if (pCache != NULL)
02318                 (*pCache)[Distance] = PointInfo;
02319 #endif
02320             //TRACEUSER( "Diccon", _T("Point %d, %d found from line\n"), PointInfo.m_Point.x, PointInfo.m_Point.y);
02321             Found = TRUE;
02322         }
02323         
02324     }
02325 
02326     if (Found)
02327     {
02328         *pPoint = PointInfo.m_Point;
02329         if (pTangent)
02330             *pTangent = PointInfo.m_Tangent;
02331         
02332     }
02333 
02334 
02335     if (Found == FALSE)
02336         TRACEUSER( "Diccon", _T("Not found at distance %d\n"), Distance);
02337     return Found;
02338 }
02339 
02340 
02341 /********************************************************************************************
02342 >   void PathProcessorBrush::Reset
02343 
02344     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02345     Created:    30/4/99
02346     Inputs:     -           
02347     Outputs:    -
02348     Returns:    -
02349     Purpose:    Sets the various members etc. to the values that they must hold at the beginning
02350                 of any of the following:
02351                 - Rendering;
02352                 - Bounding box calculation;
02353                 - Convert to shapes;
02354                 - GetObjectCount;
02355 ********************************************************************************************/
02356 
02357 void PathProcessorBrush::Reset()
02358 {
02359     // set members to record variations for each step
02360     m_LastScaling = m_BrushScaling;
02361     m_LastScalingRendered = m_BrushScaling;
02362     m_LastSpacing = m_BrushSpacing;
02363     m_LastOffset  = m_PathOffsetValue;
02364     m_LastAngle   = m_RotateAngle;
02365     m_AltValue    = 0;
02366     m_LastObject = 0; 
02367     m_LastHueMultiplier = m_BrushHueIncrement;
02368     m_LastSatMultiplier = m_BrushSatIncrement;
02369 
02370     m_LastSpacingNoRandom = m_BrushSpacing;
02371     if (m_PathOffsetType != OFFSET_RANDOM)
02372         m_LastOffsetNoRandom  = m_PathOffsetValue;
02373     else
02374         m_LastOffsetNoRandom = 0;
02375 
02376     m_LastScalingNoRandom = m_BrushScaling;
02377     m_LastRotationNoRandom = m_RotateAngle;
02378     
02379     m_CurrentStrokeCol = DocColour(COLOUR_BLACK);
02380 
02381     // reset our random number generators
02382     ResetRandomNumberGenerators();
02383 
02384 
02385     // to find out which object comes first in the sequence we may need
02386     // to know how many objects we're going to have
02387     
02388     UINT32 NumObjects = 1;
02389     BrushDefinition* pDef = GetOurBrushDefinition();
02390     ERROR3IF(pDef == NULL, "No brush definition in PathProcessorBrush::Reset");
02391 
02392     if (pDef)
02393     {
02394         NumObjects = pDef->GetNumBrushObjects();
02395 
02396         switch (m_SequenceType)
02397         {
02398             case SEQ_FORWARD:
02399             case SEQ_MIRROR:
02400                 m_LastObject = 0;
02401                 m_MirrorSeqAscend = TRUE; //we always start ascending
02402                 break;
02403             case SEQ_BACKWARD:
02404                 m_LastObject = NumObjects -1;
02405                 break;
02406             case SEQ_RANDOM:
02407                 if (NumObjects > 1)
02408                     m_LastObject = GetNextInkObject(m_LastObject, NumObjects);
02409                 break;
02410             default:
02411                 ERROR3("Invalid sequence type in PathProcessorBrush::Reset");
02412         }
02413     }
02414 }
02415 
02416 /********************************************************************************************
02417 
02418 >   DocRect PathProcessorBrush::CalculateBoundingRect(Path* pPath, NodeRenderableInk* pParent) 
02419 
02420     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02421     Created:    6/10/99
02422     Inputs:     Path along which this brush will be applied
02423                 pParent - the ink node that generated pPath.
02424     Returns:    the bounding rect of the given path with the brush applied
02425     Purpose:    Calculates the bounding rect, unfortunately the only way to do this is to
02426                 do a 'fake' render.  So this function is essentially the same as processpath
02427                 but it doesn't require a render region
02428 
02429 ********************************************************************************************/
02430 
02431 DocRect PathProcessorBrush::CalculateBoundingBox(Path* pPath, NodeRenderableInk* pParent)
02432 {
02433     DocRect ReturnRect(0,0,0,0);
02434 
02435     ERROR2IF(pPath == NULL, ReturnRect, "Path is null in PathProcessorBrush::CalculateBoundingBox");
02436     ERROR2IF(pParent == NULL, ReturnRect, "Parent is null in PathProcessorBrush::CalculateBoundingBox");
02437 
02438     // if we are timestamping then use a different method and return
02439     if (m_pParentAttr != NULL)
02440     {
02441         if (m_pParentAttr->IsTimeStamping())
02442         {
02443             return TimeStampBoundingBox();
02444         }
02445     }
02446     BrushDefinition* pBrushDef = GetOurBrushDefinition();
02447     if (pBrushDef == NULL)
02448     {
02449         return ReturnRect;
02450     }
02451     
02452     // get the definition to generate its data copies for us
02453     if (!pBrushDef->StartRender())
02454     {
02455         TRACEUSER( "Diccon", _T("Unable to start render brush for bounding box\n"));
02456         return ReturnRect;
02457     }
02458 
02459     Reset();
02460 
02461     if (m_BrushScaling <= 0)
02462         return ReturnRect;
02463 
02464     UINT32 NumBrushObjects = pBrushDef->GetNumBrushObjects();
02465     
02466     if (!PrepareForRenderingLoop(NumBrushObjects))
02467         return ReturnRect;
02468 
02469     // some variables to keep track of where we are on the path
02470     double dPathLength = pPath->GetPathLength(750/2);
02471 //  double dOrigPathLength = dPathLength;
02472     MILLIPOINT PathLength = (MILLIPOINT)dPathLength;
02473     double PathProportion = 0.0;
02474 
02475     // this records the distance along the path at which we want to find a point
02476     MILLIPOINT DistanceToPoint = 10;
02477     
02478     // declare some locals that we need in the loop
02479     MILLIPOINT Spacing = m_BrushSpacing;
02480     CPathPointInfo PathPoint;
02481     double Angle;
02482     DocCoord Point; 
02483     BOOL ok = FALSE;
02484 //  BOOL Found = TRUE;
02485     UINT32 Count = 0;
02486     UINT32 BrushObjectToRender = m_LastObject;
02487 
02488     
02489     /* To get our pressure data we will use either a cache that is held by our parent attribute
02490     OR use a value function if a VariableWidthAttribute has been rendered into the render region*/ 
02491 
02492     // get our pressure data
02493     ValueFunction* pValFunc = NULL;
02494     CDistanceSampler* pPressure = GetPressureCacheAndInitialise(pParent, &pValFunc);
02495     CSampleItem TheItem; // we need this in the loop
02496 
02497     // find our line width
02498 /*  AttrLineWidth* pLineWidth = NULL;
02499     pParent->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth), (NodeAttribute**)pLineWidth);
02500     if (pLineWidth)
02501     {
02502         INT32 Width = pLineWidth->Value.LineWidth;
02503         ScaleToValue(Width, !m_bValidPressure);
02504     }
02505 */
02506     m_bRenderAllAttributes = TRUE;
02507 
02508     m_CachedRect = DocRect(0,0,0,0);
02509     m_bCalculateRect = TRUE;
02510 
02511     TRACEUSER( "Diccon", _T("About to calculate bounding box\n"));
02512     
02513     // get the first spacing and scaling values
02514     m_UseActualScaling = TRUE;
02515     m_CurrentScaling = GetNextScaling(Count);
02516     m_LastScalingRendered = m_CurrentScaling;
02517     
02518     Spacing = GetNextSpacing();
02519     
02520     
02521     while (DistanceToPoint < PathLength)
02522     {
02523     //  TRACEUSER( "Diccon", _T("Count %d\n"), Count);
02524         // try and get the point    
02525         ok = GetPointAtDistance(pPath, DistanceToPoint, &Point, &Angle);
02526         
02527         if (ok)  
02528         {
02529             GetNextAngle();
02530             SetNextOffsetType();
02531             GetNextOffset();
02532                 
02533             if (m_CurrentScaling > 0)
02534                 RenderBrushAtPoint(Point, Angle,
02535                          BrushObjectToRender, Count,  NULL);
02536             Count++;
02537 
02538             // get the index of the next object.
02539             if (NumBrushObjects > 1)
02540                 BrushObjectToRender = GetNextInkObject(BrushObjectToRender, NumBrushObjects);
02541             
02542             DecideWhetherToUseActualScaling(BrushObjectToRender);
02543         }
02544     
02545         if (pPressure != NULL)
02546         {
02547             if (pPressure->GetNext(&TheItem))
02548             {   
02549                 if (TheItem.m_Pressure < 0 || TheItem.m_Pressure > MAXPRESSURE)
02550                 {
02551                     //ERROR3("Invalid pressure in PathProcessorBrush::CalculateBoundingBox");
02552                     //TRACEUSER( "Diccon", _T("Invalid pressure %d at count %d\n"), TheItem.m_Pressure, Count);
02553                 }
02554                 else
02555                 {
02556                     m_CurrentPressure.m_Pressure = TheItem.m_Pressure;
02557                     //RACEUSER("Diccon", "BBox pressure %d, = %d\n", Count, m_CurrentPressure.m_Pressure);
02558                 }
02559             }
02560         //  else
02561         //      ERROR3("Unable to get pressure item in PathProcessorBrush::CalculateBoundingBox");
02562         }
02563 #ifdef SCALESPACING     
02564         DistanceToPoint += (MILLIPOINT)(Spacing * m_LastScaling);
02565         
02566         if (pPressure)
02567             pPressure->SetSampleRateFromSpacing((INT32)(Spacing * m_CurrentScaling));
02568 #else
02569         DistanceToPoint += (MILLIPOINT)(Spacing * m_BrushScaling);
02570         
02571         if (pPressure)
02572             pPressure->SetSampleRateFromSpacing((INT32)(Spacing * m_CurrentScaling));
02573 #endif  
02574         
02575         // get the next distance
02576         Spacing = GetNextSpacing();
02577         m_LastScalingRendered = m_pLastScalingRendered[BrushObjectToRender];
02578 
02579         if (pValFunc != NULL)
02580         {
02581             PathProportion = (double)DistanceToPoint / dPathLength;
02582             m_CurrentPressure.m_Pressure = GetNextSampleItem(NULL, pValFunc, PathProportion).m_Pressure;
02583             if (m_CurrentPressure.m_Pressure > MAXPRESSURE)
02584                 m_CurrentPressure.m_Pressure = MAXPRESSURE;
02585         }
02586 
02587         m_CurrentScaling = GetNextScaling(Count);
02588 
02589         // we're now allowed to go to zero scaling, but if we do so we must stop rendering
02590         if (m_CurrentScaling <= 0)
02591             break;
02592 
02593         // this member keeps track of which side we should offset on if we have
02594         // an alternating offset
02595         if (m_AltValue == 0)
02596             m_AltValue = 1;
02597         else
02598             m_AltValue = 0;
02599     
02600     }
02601 
02602     /*some more awful hacks
02603     if (!m_CachedRect.IsEmpty() && (!pBrushDef->BrushContainsGroup()))
02604     {
02605         DocRect InkRect = pBrushDef->GetLargestBoundingBox();
02606         MILLIPOINT Height = (MILLIPOINT)(InkRect.Height() * m_BrushScaling);
02607         MILLIPOINT Width = (MILLIPOINT)(InkRect.Width() * m_BrushScaling);
02608     }
02609     */
02610 //  TRACEUSER( "Diccon", _T("Bounding rect: Height = %d, Width = %d\n"), m_CachedRect.Height(), m_CachedRect.Width());
02611     m_bCalculateRect = FALSE;   
02612     TRACEUSER( "Diccon", _T("Finished bounding box\n"));
02613     CleanUpAfterRender();
02614     pBrushDef->StopRender();
02615 
02616     return m_CachedRect;
02617 }   
02618     
02619 
02620 /********************************************************************************************
02621 
02622 >   DocRect PathProcessorBrush::TimeStampBoundingBox() 
02623 
02624     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02625     Created:    6/10/99
02626     Inputs:     Path along which this brush will be applied
02627     Returns:    the bounding rect of the given path with the brush applied
02628     Purpose:    Calculates the bounding rect, unfortunately the only way to do this is to
02629                 do a 'fake' render.  So this function is essentially the same as processpath
02630                 but it doesn't require a render region
02631 
02632 ********************************************************************************************/
02633 
02634 DocRect PathProcessorBrush::TimeStampBoundingBox()
02635 {
02636     if (m_pParentAttr == NULL)
02637     {
02638         //ERROR3("Parent attribute is null");
02639         return DocRect(0,0,0,0);
02640     }
02641 
02642     BrushDefinition* pBrushDef = GetOurBrushDefinition();
02643     if (pBrushDef == NULL)
02644     {
02645         ERROR3("No brush definition");
02646         return DocRect(0,0,0,0);
02647     }
02648 
02649     UINT32 NumBrushObjects = pBrushDef->GetNumBrushObjects();
02650     
02651     // seed the sequence random number generator
02652     if (m_SequenceType == SEQ_RANDOM)
02653         srand(m_SequenceRandSeed);
02654 
02655     // reset our random number generators
02656     ResetRandomNumberGenerators();
02657         
02658     // declare some locals that we need in the loop
02659 //  BOOL ok = FALSE;
02660 //  BOOL Found = TRUE;
02661     UINT32 Count = 0;
02662     UINT32 BrushObjectToRender = 0;
02663     
02664 
02665     // get the list from our attribvute
02666     TimeStampList* pTimeStampList = m_pParentAttr->GetTimeStampList();
02667     if (pTimeStampList == NULL || pTimeStampList->empty())
02668     {
02669         ERROR3("No Timestamp list");
02670         return DocRect(0,0,0,0);
02671     }
02672     TimeStampList::iterator ListPos = pTimeStampList->begin();
02673     TimeStampBrushPoint TSBP;
02674 //  PressureList* pPressure = m_pParentAttr->GetPressureCache();
02675 //  POSITION PressurePos;
02676 //  if (pPressure != NULL)
02677 //      PressurePos = pPressure->GetHeadPosition();
02678 
02679     m_bCalculateRect = TRUE;
02680     m_CachedRect = DocRect(0,0,0,0);
02681     while (ListPos != pTimeStampList->end())
02682     {
02683         TSBP = *ListPos++;
02684         
02685         m_CurrentScaling = GetNextScaling(Count);
02686     //  if (pPressure != NULL)
02687     //  {
02688 //          if (PressurePos != NULL)
02689     //          m_CurrentPressure = 127; //pPressure->GetNext(PressurePos);
02690     //  }
02691 
02692     
02693         RenderBrushAtPoint(TSBP.m_Point, TSBP.m_Tangent,
02694                    BrushObjectToRender, Count,  NULL);
02695             
02696         
02697         if (NumBrushObjects > 1)
02698                 BrushObjectToRender = GetNextInkObject(BrushObjectToRender, NumBrushObjects);
02699         Count++;
02700             
02701         // this member keeps track of which side we should offset on if we have
02702         // an alternating offset
02703         if (m_AltValue == 0)
02704             m_AltValue = 1;
02705         else
02706             m_AltValue = 0;
02707     }
02708 
02709     return m_CachedRect;
02710 
02711 }
02712 
02713 
02714 /********************************************************************************************
02715 
02716 >   void PathProcessorBrush::SetCalculateBoundingBox(BOOL Set) 
02717 
02718     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02719     Created:    6/10/99
02720     Inputs:     value to set
02721     Returns:    -
02722     Purpose:    Sets the flag indicating whether or not to calculate the bounding rect on the
02723                 next pass through RenderBrushAtPoint
02724 
02725 ********************************************************************************************/
02726 
02727 void PathProcessorBrush::SetCalculateBoundingBox(BOOL Set)
02728 {
02729     m_bCalculateRect = Set;
02730 }
02731 
02732 
02733 /********************************************************************************************
02734 
02735 >   DocRect PathProcessorBrush::GetCachedRect()
02736 
02737     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02738     Created:    6/10/99
02739     Inputs:     -
02740     Returns:    the cached bounding rect
02741     Purpose:    access fn.
02742 ********************************************************************************************/
02743 
02744 DocRect PathProcessorBrush::GetCachedRect()
02745 {
02746     return m_CachedRect;
02747 }
02748 
02749 /********************************************************************************************
02750 
02751 >   BOOL PathProcessorBrush::DoBecomeA(BecomeA* pBecomeA, Path* pPath, Node* pParent)
02752 
02753     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02754     Created:    17/3/2000
02755     Inputs:     pBecomeA - the object that tells us what to become, and recieves the results
02756                 pPath - the path that we are processing
02757                 pParent- the node that this brush is applied to
02758     Outputs:    
02759     Returns:    TRUE if everything went ok,
02760     Purpose:    To convert our brush into its individual paths and attributes, very similar
02761                 to the bounding box routine in that we extract the path from our parent node
02762                 and use it to calculate our blenpaths etc.
02763         
02764 ********************************************************************************************/
02765 
02766 BOOL PathProcessorBrush::DoBecomeA(BecomeA* pBecomeA, Path* pPath, Node* pParent)
02767 {
02768     ERROR2IF(pBecomeA == NULL, FALSE, "BecomeA pointer is NULL in PathProcessorBrush::DoBecomeA");
02769     ERROR2IF(pParent == NULL, FALSE, "Parent is NULL in PathProcessorBrush::DoBecomeA");
02770     ERROR2IF(pPath == NULL, FALSE, "Path is NULL in PathProcessorBrush::DoBecomeA");
02771 
02772     BeginSlowJob();
02773 
02774     TRACEUSER( "Diccon", _T("ABOUT TO BECOME A\n"));
02775 
02776     BrushDefinition* pBrushDef = GetOurBrushDefinition();
02777     if (pBrushDef == NULL)
02778     {
02779         return FALSE;
02780     }
02781     if (!pBrushDef->StartRender())
02782         return FALSE;
02783 
02784     UINT32 NumBrushObjects = pBrushDef->GetNumBrushObjects();
02785     if (!PrepareForRenderingLoop(NumBrushObjects))
02786         return FALSE;
02787     Reset();
02788 
02789     if (m_BrushScaling <= 0)
02790         return TRUE;
02791 
02792     // some variables to keep track of where we are on the path
02793     double dPathLength = pPath->GetPathLength(750/2);
02794     double dOrigPathLength = dPathLength;
02795     MILLIPOINT PathLength = (MILLIPOINT)dPathLength;
02796     double PathProportion = 0.0;
02797     
02798     // this records the distance along the path at which we want to find a point
02799     MILLIPOINT DistanceToPoint = 0;
02800     
02801     // declare some locals that we need in the loop
02802     MILLIPOINT Spacing = m_BrushSpacing;
02803     CPathPointInfo PathPoint;
02804     double Angle;
02805     DocCoord Point; 
02806     BOOL ok = FALSE;
02807 //  BOOL Found = TRUE;
02808     UINT32 Count = 0;
02809     UINT32 BrushObjectToRender = m_LastObject;
02810     
02811     m_bRenderAllAttributes = TRUE;
02812     
02813     if (pPath->IsClosed())
02814     {
02815         // if the path is closed then hopefully we will have adjusted the spacing so that the
02816         // path length fits an integer number of objects.  However we do not want to render
02817         // two objects on the start point so reduce the path length we actually use
02818         double ActualSpacing = m_BrushScaling * (double)m_BrushSpacing;
02819 
02820         PathLength -= (MILLIPOINT)(ActualSpacing * 0.2); // we need some margin for error
02821         dPathLength = (double)PathLength;
02822         AdjustSpacingForClosedPath(pPath, dOrigPathLength);
02823 
02824         if (pParent->IsARegularShape())
02825             pPath->Reverse();
02826 
02827     }
02828 
02829     // get our pressure data
02830     ValueFunction* pValFunc = NULL;
02831     CDistanceSampler* pPressure = GetPressureCacheAndInitialise((NodeRenderableInk*)pParent, &pValFunc);
02832     CSampleItem TheItem; // we need this in the loop
02833 
02834     // make an object to deal with the blendpaths etc
02835     HandleBrushBecomeA HandleBecomeA;
02836     HandleBecomeA.SetSecondary(pBecomeA->IsSecondary());
02837 
02838     // Allocate a new group to hold all our objects
02839     UndoableOperation* pUndoOp = pBecomeA->GetUndoOp();
02840     NodeRenderableInk* pContext = (NodeRenderableInk*)pParent;
02841     NodeGroup* pNodeGroup = NULL;
02842     
02843     // we need a new group node if we are replacing the brush or passing back to BrushBecomeAGroup
02844     if (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->IsBrushBecomeAGroup())
02845     {   
02846         ALLOC_WITH_FAIL(pNodeGroup, (new NodeGroup), pUndoOp); 
02847         if (pNodeGroup == NULL)
02848             return FALSE;
02849     
02850         pContext = pNodeGroup;
02851     }
02852     
02853     
02854     if (pBecomeA->GetReason() == BECOMEA_REPLACE)
02855     {
02856         // insert the new group next to our parent
02857         if (pUndoOp)
02858         {
02859             BOOL ok = TRUE;
02860             // If we don't own the parent node, we should insert after (on top of) it
02861             if (pBecomeA->IsSecondary())
02862                 ok = pUndoOp->DoInsertNewNode(pContext,pParent,NEXT,FALSE,FALSE,FALSE,FALSE);
02863             else
02864                 ok = pUndoOp->DoInsertNewNode(pContext,pParent,PREV,FALSE,FALSE,FALSE,FALSE);
02865 
02866             if (!ok)
02867             {
02868                 delete pNodeGroup;
02869                 return FALSE;
02870             }
02871         }
02872         else
02873         {
02874             pContext->AttachNode(pParent, PREV);
02875         }
02876 
02877         HandleBecomeA.Initialise(pBecomeA, pNodeGroup, pParent);
02878     }
02879     else
02880         HandleBecomeA.Initialise(pBecomeA, pContext, pParent);
02881 
02882     // we need the local stroke colour
02883     NodeAttribute* pStrokeColour = NULL;
02884     
02885     // get the attribute
02886     ((NodeRenderableInk*)pParent)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), &pStrokeColour);
02887 
02888     if (pStrokeColour != NULL)
02889     {
02890 
02891         // get the stroke colour
02892         StrokeColourAttribute* pVal = (StrokeColourAttribute*)pStrokeColour->GetAttributeValue();
02893         if (pVal != NULL)
02894             m_CurrentStrokeCol = pVal->Colour;
02895     }
02896     
02897     // get the first spacing and scaling values
02898     m_UseActualScaling = TRUE;
02899     m_CurrentScaling = GetNextScaling(Count);
02900     m_LastScalingRendered = m_CurrentScaling;
02901 
02902     Spacing = GetNextSpacing();
02903     while (DistanceToPoint < PathLength)
02904     {
02905     //  TRACEUSER( "Diccon", _T("Count %d\n"), Count);
02906         // try and get the point 
02907         ok = GetPointAtDistance(pPath, DistanceToPoint, &Point, &Angle);
02908         GetNextAngle();
02909         GetNextOffset();
02910         GetNextHueMultiplier();
02911         GetNextSaturationMultiplier();
02912         if (ok)  
02913         {
02914             SetNextOffsetType();
02915 
02916             if (m_CurrentScaling > 0)
02917                 RenderBrushAtPoint(Point, Angle,
02918                          BrushObjectToRender, Count,  NULL, &HandleBecomeA);
02919 
02920             // get the next pressure value
02921             if (pPressure != NULL)
02922             {
02923                 double pLength = dOrigPathLength;       // Don't keep calling pPath->GetPathLength(); It's complex!
02924                 double pDataLength = pPressure->GetDistanceRep (), count = pPressure->GetCount ();
02925                 double dataRatio = 1.0;
02926 
02927                 if (pDataLength < pLength)
02928                 {
02929                     dataRatio = pDataLength / pLength;
02930                 }
02931                 else
02932                 {
02933                     dataRatio = pLength / pDataLength;
02934                 }
02935 
02936                 double offset = 1.0;
02937                     
02938                 if (DistanceToPoint < pLength)
02939                 {
02940                     offset = (DistanceToPoint / pLength) * dataRatio * count;
02941                 }
02942                 else
02943                 {
02944                     offset = (pLength / DistanceToPoint) * dataRatio * count;
02945                 }
02946                 
02947                 if (pPressure->GetAtPos (offset, &TheItem))//GetNext(&TheItem))
02948                 {
02949                     if (TheItem.m_Pressure < MAXPRESSURE)
02950                         m_CurrentPressure.m_Pressure = TheItem.m_Pressure;
02951                     else
02952                         m_CurrentPressure.m_Pressure = MAXPRESSURE;
02953                 //  TRACEUSER( "Diccon", _T("Pressure = %d\n"), TheItem.m_Pressure);
02954                 }
02955             }
02956     
02957             Count++;
02958         
02959             // get the index of the next object.
02960             if (NumBrushObjects > 1)
02961                 BrushObjectToRender = GetNextInkObject(BrushObjectToRender, NumBrushObjects);
02962 
02963             DecideWhetherToUseActualScaling(BrushObjectToRender);
02964         }
02965 #ifdef SCALESPACING     
02966         DistanceToPoint += (MILLIPOINT)(Spacing * m_LastScaling);
02967         
02968         if (pPressure)
02969             pPressure->SetSampleRateFromSpacing((INT32)(Spacing * m_CurrentScaling));
02970 #else
02971             DistanceToPoint += (MILLIPOINT)(Spacing * m_BrushScaling);
02972         
02973         if (pPressure)
02974             pPressure->SetSampleRateFromSpacing(Spacing);
02975 #endif
02976         
02977         if (pValFunc != NULL)
02978         {
02979             PathProportion = (double)DistanceToPoint / dPathLength;
02980             m_CurrentPressure.m_Pressure = GetNextSampleItem(NULL, pValFunc, PathProportion).m_Pressure;
02981             if (m_CurrentPressure.m_Pressure > MAXPRESSURE)
02982                 m_CurrentPressure.m_Pressure = MAXPRESSURE;
02983         }
02984 
02985         // get the next distance
02986         Spacing = GetNextSpacing();
02987         m_LastScalingRendered = m_pLastScalingRendered[BrushObjectToRender];
02988         m_CurrentScaling = GetNextScaling(Count);
02989         
02990         // this member keeps track of which side we should offset on if we have
02991         // an alternating offset
02992         if (m_AltValue == 0)
02993             m_AltValue = 1;
02994         else
02995             m_AltValue = 0;
02996     
02997     }
02998     
02999     pBrushDef->StopRender();
03000 
03001     CleanUpAfterRender();
03002     TRACEUSER( "Diccon", _T("FINISHED BRUSH DOBECOMEA\n"));
03003 
03004     if (pBecomeA->GetReason() == BECOMEA_REPLACE)
03005     {
03006         HandleBecomeA.FinishPassback();             // Call passback even in Replace mode to inform handler of
03007                                                     // location of new object(s) in document
03008         return HandleBecomeA.HideCreatedByNode();   // hide the original node 
03009     }
03010     else
03011         return HandleBecomeA.FinishPassback();
03012 
03013     return FALSE;
03014 }
03015 
03016 
03017 /********************************************************************************************
03018 
03019 >   virtual BOOL PathProcessor::DoesActuallyDoAnything(RenderRegion* pRender)
03020 
03021     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03022     Created:    1/10/2000
03023     Inputs:     pRender - pointer to the render region that we are about to render our path into
03024     Returns:    TRUE if it is anticipated that this path processor will alter the path in any
03025                 way, FALSE if not
03026     Purpose:    To determine whether or not our path processor is 'default' i.e. if does not 
03027                 change the path at all.  If so then the render region will be free to use
03028                 DrawPathToOutputDevice which will let us use dash patterns, arrowheads etc.
03029     
03030     Errors:     
03031 
03032 ********************************************************************************************/
03033 
03034 BOOL PathProcessorBrush::DoesActuallyDoAnything(RenderRegion* pRender)
03035 {
03036     if (pRender == NULL)
03037     {
03038         ERROR3("No render region supplied to PathProcessorBrush::DoesActuallyDoAnything");
03039         return FALSE;
03040     }
03041 
03042     // get the line width , if its too small we don't want to draw anything
03043     LineWidthAttribute* pLine = (LineWidthAttribute*)pRender->GetCurrentAttribute(ATTR_LINEWIDTH);
03044     
03045     if (pLine && pLine->LineWidth < 500)
03046         return FALSE;
03047 
03048     // if we have a transparent stroke colour then don't bother either
03049     StrokeColourAttribute* pStroke = (StrokeColourAttribute*)pRender->GetCurrentAttribute(ATTR_STROKECOLOUR);
03050     
03051     if (pStroke && pStroke != NULL)
03052     {
03053         if (pStroke->Colour.IsTransparent())
03054             return FALSE;
03055     }
03056     return TRUE;
03057 }
03058 
03059 /********************************************************************************************
03060 
03061 >   virtual BrushDefinition* PathProcessorBrush::GetOurBrushDefinition() 
03062 
03063     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03064     Created:    6/10/99
03065     Returns:    the brush definition corresponding to our brush handle
03066     Purpose:    As above
03067 
03068 ********************************************************************************************/
03069 
03070 BrushDefinition* PathProcessorBrush::GetOurBrushDefinition()
03071 {
03072     // first check to see that we have been assigned a brush
03073     if (m_BrushHandle == BrushHandle_NoBrush)
03074     {
03075         //ERROR3("This processor has not been assigned a brush");
03076         return NULL;
03077     }
03078 
03079     return BrushComponent::FindBrushDefinition(m_BrushHandle);
03080 
03081 }
03082 
03083 /********************************************************************************************
03084 
03085 >   virtual BOOL PathProcessorBrush::IsDifferent(PathProcessorBrush *pOther);
03086 
03087     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03088     Created:    13/12/99
03089 
03090     Inputs:     pOther - The other PathProcessorBrush
03091 
03092     Returns:    TRUE if they're considered different, FALSE if they are equivalent
03093 
03094     Purpose:    Equality operator
03095 
03096     Notes:      The base class implementation compares the runtime classes of the
03097                 2 objects to see if they are different classes. If they are the same
03098                 class, it assumes they're cnsidered equal - derived classes should
03099                 override this behaviour if further comparisons are necessary.
03100 
03101 ********************************************************************************************/
03102 
03103 BOOL PathProcessorBrush::IsDifferent(PathProcessorBrush *pOther)
03104 {
03105     ERROR3IF(pOther == NULL, "Illegal NULL param");
03106 
03107     if (GetRuntimeClass() != pOther->GetRuntimeClass())
03108         return(TRUE);
03109 
03110     // compare all the members
03111     if ( 
03112            (m_BrushHandle           != pOther->GetBrushDefinitionHandle())
03113         || (m_BrushSpacing          != pOther->GetSpacing())
03114         || (m_BrushSpacingIncrConst != pOther->GetSpacingIncrConst())
03115         || (m_BrushSpacingIncrProp  != pOther->GetSpacingIncrProp())
03116         || (m_BrushSpacingMaxRand   != pOther->GetSpacingMaxRand())
03117         || (m_BrushSpacingRandSeed  != pOther->GetSpacingRandSeed())
03118         || (m_BrushScaling          != pOther->GetBrushScaling())
03119         || (m_BrushScalingIncr      != pOther->GetBrushScalingIncr())
03120         || (m_BrushScalingIncrConst != pOther->GetBrushScalingIncrConst())
03121         || (m_BrushScalingMaxRand   != pOther->GetScalingMaxRand())
03122         || (m_BrushScalingRandSeed  != pOther->GetScalingRandSeed())
03123         || (m_RotateAngle           != pOther->GetRotationAngle())
03124         || (m_RotAngleIncrConst     != pOther->GetRotationIncrConst())
03125         || (m_RotationMaxRand       != pOther->GetRotationMaxRand())
03126         || (m_RotationRandSeed      != pOther->GetRotationRandSeed())
03127         || (m_bTile                 != pOther->IsTiled())
03128         || (m_bRotate               != pOther->IsRotated())
03129         || (m_PathOffsetType        != pOther->GetPathOffsetType())
03130         || (m_PathOffsetValue       != pOther->GetPathOffsetValue())
03131         || (m_PathOffsetIncrConst   != pOther->GetPathOffsetIncrConst())
03132         || (m_PathOffsetIncrProp    != pOther->GetPathOffsetIncrProp())
03133         || (m_OffsetValueMaxRand    != pOther->GetOffsetValueMaxRand())
03134         || (m_OffsetValueRandSeed   != pOther->GetOffsetValueRandSeed())
03135         || (m_OffsetTypeRandSeed    != pOther->GetOffsetTypeRandSeed())
03136         || (m_SequenceType          != pOther->GetSequenceType())
03137         || (m_SequenceRandSeed      != pOther->GetSequenceSeed())
03138         || (m_bUseLocalFillColour   != pOther->GetUseLocalFillColour())
03139         || (m_bUseLocalTransp       != pOther->GetUseLocalTransp())
03140         || (m_bUseNamedColours      != pOther->GetUseNamedColours())
03141         )
03142         return TRUE;
03143     
03144     // must be the same
03145     return(FALSE);
03146 }
03147 
03148 
03149 
03150 /********************************************************************************************
03151 
03152 >   virtual PathProcessorBrush *PathProcessorBrush::Clone(void)
03153 
03154     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03155     Created:    13/12/99
03156 
03157     Returns:    NULL if we're out of memory, else
03158                 a pointer to a clone (exact copy) of this object
03159 
03160     Purpose:    To copy PathProcessorBrush or derived-class object
03161 
03162 ********************************************************************************************/
03163 
03164 PathProcessorBrush *PathProcessorBrush::Clone(void)
03165 {
03166 
03167     // Clone this object 
03168     PathProcessorBrush *pClone = new PathProcessorBrush;
03169 
03170     if (pClone == NULL)
03171         return NULL;
03172 
03173     // copy the data
03174     pClone->SetBrushDefinition(m_BrushHandle);
03175     pClone->SetPathOffsetType(m_PathOffsetType);
03176     pClone->SetPathOffsetValue(m_PathOffsetValue);
03177     pClone->SetRotated(m_bRotate);
03178     pClone->SetRotationAngle(m_RotateAngle);
03179     pClone->SetRotationIncrConst(m_RotAngleIncrConst);
03180     pClone->SetRotationIncrProp(m_RotAngleIncrProp);
03181     pClone->SetRotationMaxPressure(m_RotationMaxPressure);
03182 
03183     pClone->SetSpacing(m_BrushSpacing);
03184     pClone->SetTiling(m_bTile);
03185     pClone->SetBrushScaling(m_BrushScaling);
03186     pClone->SetBrushScalingIncr(m_BrushScalingIncr);
03187     pClone->SetBrushScalingIncrConst(m_BrushScalingIncrConst);
03188     pClone->SetMaxScaling(m_MaxScaling);
03189     pClone->SetScalingMaxPressure(m_ScalingMaxPressure);
03190     pClone->SetSpacingIncrProp(m_BrushSpacingIncrProp);
03191     pClone->SetSpacingIncrConst(m_BrushSpacingIncrConst);
03192     pClone->SetSpacingMaxPressure(m_SpacingMaxPressure);
03193     pClone->SetPathOffsetIncrConst(m_PathOffsetIncrConst);
03194     pClone->SetPathOffsetIncrProp(m_PathOffsetIncrProp);
03195     pClone->SetSpacingMaxRand(m_BrushSpacingMaxRand);
03196     pClone->SetSpacingRandSeed(m_BrushSpacingRandSeed);
03197     pClone->SetScalingMaxRand(m_BrushScalingMaxRand);
03198     pClone->SetScalingRandSeed(m_BrushScalingRandSeed);
03199     pClone->SetSequenceType(m_SequenceType);
03200     pClone->SetSequenceSeed(m_SequenceRandSeed);
03201     pClone->SetOffsetValueMaxRand(m_OffsetValueMaxRand);
03202     pClone->SetOffsetValueRandSeed(m_OffsetValueRandSeed);
03203     pClone->SetOffsetTypeRandSeed(m_OffsetTypeRandSeed);
03204 
03205     pClone->SetRotationMaxRand(m_RotationMaxRand);
03206     pClone->SetRotationRandSeed(m_RotationRandSeed);
03207 
03208     pClone->SetUseLocalFillColour(m_bUseLocalFillColour);
03209     pClone->SetUseLocalTransp(m_bUseLocalTransp);
03210     pClone->SetUseNamedColours(m_bUseNamedColours);
03211     
03212     pClone->SetHueIncrement(m_BrushHueIncrement);
03213     pClone->SetHueMaxRand(m_BrushHueMaxRand);
03214     pClone->SetHueRandSeed(m_BrushHueRandSeed);
03215     pClone->SetSatIncrement(m_BrushSatIncrement);
03216     pClone->SetSatMaxRand(m_BrushSatMaxRand);
03217     pClone->SetSatRandSeed(m_BrushSatRandSeed); 
03218 
03219     pClone->SetBrushTransparency(m_BrushTransparency);
03220     pClone->SetTransparencyPressure(m_TranspMaxPressure);
03221 
03222     pClone->SetParentAttribute(m_pParentAttr);
03223     
03224     return(pClone);
03225 }
03226 
03227 
03228 /********************************************************************************************
03229 
03230 >   void PathProcessorBrush::SetBrushDefinition(BrushHandle Handle)
03231 
03232     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03233     Created:    29/2/97
03234 
03235     Purpose:    Sets this path processor up to use the given vector Brush definition
03236                 in all future rendering. 
03237 
03238     Notes:      If not set, or if set to BrushHandle_NoBrush, the Brush processor
03239                 will render its Brushs as simple (flat filled) Brushs by calling the
03240                 base class ProcessPath method.
03241 
03242 ********************************************************************************************/
03243 
03244 void PathProcessorBrush::SetBrushDefinition(BrushHandle Handle)
03245 {
03246     m_BrushHandle = Handle; 
03247 }
03248 
03249 
03250 
03251 /********************************************************************************************
03252 
03253 >   BrushHandle PathProcessorBrush::GetBrushDefinitionHandle()
03254 
03255     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03256     Created:    14/12/99
03257     Inputs:     -
03258     Returns:    the handle currently used by this pathprocessor
03259     Purpose:    As above
03260 
03261 ********************************************************************************************/
03262 
03263 BrushHandle PathProcessorBrush::GetBrushDefinitionHandle()
03264 {
03265     return m_BrushHandle;
03266 }
03267 
03268 
03269 /********************************************************************************************
03270 
03271 >   void PathProcessorBrush::SwitchAlternateValue()
03272 
03273     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03274     Created:    14/12/99
03275     Inputs:     -
03276     Returns:    switches the alternating flag used to determine which side of the path the 
03277                 offset is on.  If you are using this PPB by calling RenderBrushAtPoint directly
03278                 rather than passing in a path to ProcessPath and you want to have an alternating
03279                 offset then you need to call this prior to RenderBrushAtPoint.
03280     Purpose:    
03281 
03282 ********************************************************************************************/
03283 
03284 void PathProcessorBrush::SwitchAlternateValue()
03285 {
03286     if (m_AltValue == 0)
03287         m_AltValue = 1;
03288     else
03289         m_AltValue = 0;
03290 }
03291 
03292 
03293 /********************************************************************************************
03294 
03295 >   INT32 PathProcessorBrush::GetObjectCountToDistance(MILLIPOINT Distance)
03296 
03297     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03298     Created:    23/5/2000
03299     Inputs:     Distance along the path to find the object count for
03300     Returns:    the number of brush objects in the distance provided.
03301     Purpose:    To find out how many brush objects we will have in the distance given.  
03302 
03303 ********************************************************************************************/
03304 
03305 INT32 PathProcessorBrush::GetObjectCountToDistance(MILLIPOINT Distance)
03306 {
03307     if (Distance < 0)
03308         return -1;
03309     Reset();  // set our RNG back to the start
03310     MILLIPOINT DistanceSoFar = 0;
03311     INT32 Count = 0;
03312     while (DistanceSoFar < Distance)
03313     {
03314         DistanceSoFar += GetNextSpacing();
03315         Count++;
03316     }
03317     return Count;
03318 }
03319 
03320 
03321 /********************************************************************************************
03322 
03323 >   MILLIPOINT PathProcessorBrush::GetDistanceToObject(UINT32 ObjectNum)
03324 
03325     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03326     Created:    23/5/2000
03327     Inputs:     ObjectNum - the object number that we want to get to
03328     Returns:    the distance along a path that we have to go before we reach ObjectNum
03329     Purpose:    Finds out at what we distance we place the ObjectNum'th object
03330 
03331 ********************************************************************************************/
03332 
03333 MILLIPOINT PathProcessorBrush::GetDistanceToObject(UINT32 ObjectNum)
03334 {
03335     MILLIPOINT Distance = 0;
03336     UINT32 ObjectCounter = 0;
03337 
03338     Reset(); // reset our RNG
03339 
03340     while (ObjectCounter < ObjectNum)
03341     {
03342         Distance += GetNextSpacing();
03343         ObjectCounter++;
03344     }
03345     return Distance;
03346 }
03347 
03348 /********************************************************************************************
03349 
03350 >   MILLIPOINT PathProcessorBrush::GetSpacingAtDistance(MILLIPOINT Distance)
03351 
03352     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03353     Created:    23/5/2000
03354     Inputs:     Distance along the path 
03355     Returns:    the spacing to the next object, or -1 if Distance is invalid
03356     Purpose:    If we are Distance along our path then thif function finds out how far it
03357                 would be to the next brush object.
03358 
03359 ********************************************************************************************/
03360 
03361 MILLIPOINT PathProcessorBrush::GetSpacingAtDistance(MILLIPOINT Distance)
03362 {
03363     if (Distance < 0)
03364         return -1;
03365 
03366     Reset(); // set our RNG
03367 
03368     MILLIPOINT DistanceSoFar = 0;
03369     
03370     while (DistanceSoFar <= Distance)
03371     {
03372         DistanceSoFar+= GetNextSpacing();
03373     }
03374 
03375     MILLIPOINT SpacingGap = DistanceSoFar - Distance;
03376     TRACEUSER( "Diccon", _T("Spacing at distance = %d\n"), SpacingGap);
03377     return SpacingGap;
03378 }
03379 
03380 
03381 /********************************************************************************************
03382 
03383 >   BOOL GetSpacingAndScalingAtDistance(MILLIPOINT Distance, MILLIPOINT* pSpacing, double* pScaling,
03384                                         UINT32* pPressure)
03385 
03386     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03387     Created:    5/7/2000
03388     Inputs:     Distance along the path 
03389     Outputs:    pSpacing - the spacing at that distance
03390                 pScaling - the scaling at that distance
03391                 pPressure (bonus) - the pressure, defaults to NULL
03392     Returns:    the spacing to the next object, or -1 if Distance is invalid
03393     Purpose:    Retrieves the values for spacing, scaling and pressure, that are in effect at 
03394                 Distance along the path.
03395                 
03396     Notes:      This is a replacement for GetSpacingAtDistance which is necessary now that spacing
03397                 is dependant on the scaling of each brush object.  This function duplicates the 
03398                 loop found in ProcessPath, iterating through brush objects replicating the spacing and
03399                 scaling values that would be found in the render loop.
03400 
03401     2nd Note:   The spacing value is a bit of a misnomer, what we really retrieve is the distance
03402                 to the next object after Distance.  
03403 ********************************************************************************************/
03404 
03405 BOOL PathProcessorBrush::GetSpacingAndScalingAtDistance(MILLIPOINT Distance, MILLIPOINT* pSpacing, 
03406                                                         double* pScaling, UINT32* pPressure)
03407 
03408 {
03409     // some checks
03410     ERROR2IF(pSpacing == NULL, FALSE, "Invalid input to PathProcessorBrush::GetSpacingAndScalingAtDistance");
03411     ERROR2IF(pScaling == NULL, FALSE, "Invalid input to PathProcessorBrush::GetSpacingAndScalingAtDistance");
03412     ERROR2IF(Distance < 0, FALSE, "Invalid input to PathProcessorBrush::GetSpacingAndScalingAtDistance");
03413 
03414     // first reset our members so we start at the beginning
03415     Reset();
03416 
03417     // get the pressure cache from our attribute, if there is one
03418     CDistanceSampler* pSampler = GetPressureCacheAndInitialise();
03419     CSampleItem TheItem;
03420 
03421     UINT32 Count = 0;
03422     m_CurrentScaling = GetNextScaling(Count);
03423     MILLIPOINT Spacing = GetNextSpacing();
03424     MILLIPOINT DistanceSoFar = 0;  // we start at 10 MP in from the start of the path, for consistenc
03425 
03426     while (DistanceSoFar <= Distance)
03427     {
03428         // increment our distance
03429 #ifdef SCALESPACING
03430         DistanceSoFar += (MILLIPOINT)(Spacing * m_LastScaling);
03431 #else
03432         DistanceSoFar += (MILLIPOINT)Spacing;
03433 #endif
03434         
03435         // get the next pressure value, if there is one
03436         if (pSampler != NULL)
03437         {
03438             if (pSampler->GetNext(&TheItem))
03439             {
03440                 if (TheItem.m_Pressure < MAXPRESSURE)
03441                     m_CurrentPressure.m_Pressure = TheItem.m_Pressure;
03442             }
03443         }   
03444 #ifdef SCALESPACING 
03445         if (pPressure)
03446             pSampler->SetSampleRateFromSpacing((INT32)(Spacing * m_LastScaling));
03447 #else
03448         if (pPressure)
03449             pSampler->SetSampleRateFromSpacing(Spacing);
03450 #endif
03451         
03452         // get the next spacing and scaling values
03453         Spacing = GetNextSpacing();
03454         m_CurrentScaling = GetNextScaling(Count);
03455     }
03456 
03457     // we want the distance to the next brush object
03458     MILLIPOINT DistanceGap = DistanceSoFar - Distance;
03459     if (Spacing < DistanceGap)
03460         DistanceGap = Spacing;
03461 
03462     // hopefully this little hack will deal with the case when we are adding to the start of the path
03463     if (DistanceGap == 0)
03464         DistanceGap = Spacing;
03465 
03466     // assign the data we've found
03467     *pSpacing = DistanceGap;
03468     *pScaling = m_CurrentScaling;
03469     if (pPressure != NULL)
03470         *pPressure = m_CurrentPressure.m_Pressure;
03471 
03472     return TRUE;
03473 }
03474 
03475 
03476 /********************************************************************************************
03477 
03478 >   BOOL PathProcessorBrush::AdvanceBrushToDistance(MILLIPOINT Distance)
03479 
03480     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03481     Created:    5/7/2000
03482     Inputs:     Distance along the path 
03483     
03484     Returns:    TRUE, unless something goes wrong
03485     Purpose:    Advances the member variables in this PPB to the values they would acquire if 
03486                 the given distance were to be rendered.  Basically another variant on GetSpacing
03487                 AtDistance
03488 ********************************************************************************************/
03489 
03490 BOOL PathProcessorBrush::AdvanceBrushToDistance(MILLIPOINT Distance)
03491 {
03492     ERROR2IF(Distance < 0, FALSE, "Invalid input to PathProcessorBrush::GetSpacingAndScalingAtDistance");
03493     BrushDefinition* pDef = BrushComponent::FindBrushDefinition(m_BrushHandle);
03494     ERROR2IF(pDef == NULL, FALSE,"No brush definition in PathProcessorBrush::AdvanceBrushToDistance");
03495 
03496     // first reset our members so we start at the beginning
03497     Reset();
03498 
03499     // get the pressure cache from our attribute, if there is one
03500     CDistanceSampler* pSampler = GetPressureCacheAndInitialise();
03501     CSampleItem TheItem;
03502 
03503     UINT32 Count = 0;
03504     
03505     UINT32 NumBrushObjects = pDef->GetNumBrushObjects();
03506     UINT32 BrushObject = m_LastObject;
03507     if (NumBrushObjects > 1 && m_SequenceType == SEQ_RANDOM)
03508         BrushObject = GetNextInkObject(m_LastObject, NumBrushObjects);
03509 
03510     m_CurrentScaling = GetNextScaling(Count++);
03511     MILLIPOINT Spacing = GetNextSpacing();
03512     MILLIPOINT DistanceSoFar = 0;  // we start at 10 MP in from the start of the path, for consistenc
03513 
03514     while (DistanceSoFar <= Distance)
03515     {
03516         // increment our distance
03517 #ifdef SCALESPACING
03518         DistanceSoFar += (MILLIPOINT)(Spacing * m_CurrentScaling);
03519 #else
03520         DistanceSoFar += (MILLIPOINT)Spacing;
03521 #endif
03522         GetNextOffsetType();
03523         GetNextOffset();
03524         GetNextAngle();
03525         GetNextHueMultiplier();
03526         GetNextSaturationMultiplier();
03527         // get the next pressure value, if there is one
03528         if (pSampler != NULL)
03529         {
03530             if (pSampler->GetNext(&TheItem))
03531             {
03532                 if (TheItem.m_Pressure < MAXPRESSURE)
03533                     m_CurrentPressure.m_Pressure = TheItem.m_Pressure;
03534             }
03535 #ifdef SCALESPACING
03536             pSampler->SetSampleRateFromSpacing((INT32)(Spacing * m_CurrentScaling));
03537 #else
03538             pSampler->SetSampleRateFromSpacing(Spacing);
03539 #endif
03540         }   
03541         
03542         
03543         // get the next spacing and scaling values
03544         Spacing = GetNextSpacing();
03545         m_CurrentScaling = GetNextScaling(Count++);
03546 
03547         if (m_AltValue == 0)
03548             m_AltValue = 1;
03549         else
03550             m_AltValue = 0;
03551 
03552         if (NumBrushObjects > 1)
03553             BrushObject = GetNextInkObject(BrushObject, NumBrushObjects);
03554     }
03555     m_LastObject = BrushObject;
03556     return TRUE;
03557 }
03558 
03559 
03560 /********************************************************************************************
03561 
03562 >   UINT32 PathProcessorBrush::GetLastObject()
03563 
03564     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03565     Created:    5/7/2000
03566     Inputs:     -
03567     
03568     Returns:    the last object member
03569     Purpose:    The last object member keeps track of which object to render next as we proceed
03570                 along the path.
03571 ********************************************************************************************/
03572 
03573 UINT32 PathProcessorBrush::GetLastObject()
03574 {
03575     return m_LastObject;
03576 }
03577 
03578 
03579 
03580 /********************************************************************************************
03581 
03582 >   void PathProcessorBrush::AdjustSpacingForClosedPath(NodeRenderableInk* pInk)
03583 
03584     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03585     Created:    5/7/2000
03586     Inputs:     pInk - the ink node that this path processor will process
03587     
03588     Returns:    -
03589     Purpose:    When we apply a brush to a closed path we want to adjust the spacing so that 
03590                 the distance between the start object and the end object is the same as the 
03591                 distance between the start object and the second object.
03592                 Here we check to see if the ink node is a single shape that produces a closed
03593                 path (no groups etc.).  We will then get the length of that path and try 
03594                 to get the best spacing value.
03595 ********************************************************************************************/
03596 
03597 void PathProcessorBrush::AdjustSpacingForClosedPath(NodeRenderableInk* pInk)
03598 {
03599     if (pInk == NULL)
03600     {
03601         ERROR3("Ink node is NULL in PathProcessorBrush::AdjustSpacingForClosedPath");
03602         return;
03603     }
03604     if (pInk->IsCompound())
03605         return;
03606 
03607     // Use a SimpleBecomeA to get the path from the parent object
03608     SimpleBecomeA BecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), NULL);
03609         
03610     if (pInk->DoBecomeA(&BecomeA))
03611     {
03612         NodePath* pNodePath = BecomeA.GetNodePath();
03613         if (pNodePath) 
03614         {
03615             if (pNodePath->InkPath.IsClosed())
03616             {
03617                 AdjustSpacingForClosedPath(&(pNodePath->InkPath), pNodePath->InkPath.GetPathLength(750/2));
03618             }
03619 
03620             // delete the nodepath we got
03621             delete pNodePath;
03622         }
03623     }
03624         
03625 }
03626 
03627 
03628 /********************************************************************************************
03629 
03630 >   void PathProcessorBrush::AdjustSpacingForClosedPath(Path* pPath, double dPathLength)
03631 
03632     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03633     Created:    5/7/2000
03634     Inputs:     pInk - the ink node that this path processor will process
03635     
03636     Returns:    -
03637     Purpose:    When we apply a brush to a closed path we want to adjust the spacing so that 
03638                 the distance between the start object and the end object is the same as the 
03639                 distance between the start object and the second object.
03640                 Here we check to see if the ink node is a single shape that produces a closed
03641                 path (no groups etc.).  We will then get the length of that path and try 
03642                 to get the best spacing value.
03643 ********************************************************************************************/
03644 
03645 void PathProcessorBrush::AdjustSpacingForClosedPath(Path* pPath, double dPathLength)
03646 {
03647     if (pPath == NULL || !pPath->IsClosed())
03648         return;
03649     
03651             
03652     // what we want to do is set the spacing so that it places the first
03653     // and last object on the same spot
03654 
03655     // get the number of objects with the current spacing
03656     double ActualSpacing = m_BrushScaling * (double)m_BrushSpacing;
03657     INT32 NumObjects = (INT32)(dPathLength / ActualSpacing);
03658 
03659     // Ensure that the NumObjects value isn't equal to zero. This prevents a divide by
03660     // zero error from being thrown.
03661     if ( NumObjects == 0 )
03662     {
03663         NumObjects = 1;
03664     }
03665 
03666     // work out what the spacing would be if we used the whole of the path exactly
03667     double NewActualSpacing = dPathLength / (double)NumObjects;
03668     
03669     double NewSpacing = NewActualSpacing / m_BrushScaling;
03670 
03671     // set the new value
03672     SetSpacing((MILLIPOINT)NewSpacing);
03673 }
03674 
03675 /********************************************************************************************
03676 
03677 >   CDistanceSampler* PathProcessorBrush::GetPressureCacheAndInitialise()
03678 
03679     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03680     Created:    23/5/2000
03681     Inputs:     -
03682     Returns:    pointer to the pressure data held by our attribute, or NULL if we fail
03683     Purpose:    This should be called to get the pressure cache from the attribute and to 
03684                 set up the relevant members when we wish to start retrieving pressure data
03685                 from the beginning.
03686 
03687 ********************************************************************************************/
03688 
03689 CDistanceSampler* PathProcessorBrush::GetPressureCacheAndInitialise()
03690 {
03691     // initialise to NULL
03692     CDistanceSampler* pPressure = NULL;
03693     
03694     // get the cache from our parent attribute
03695     if (m_pParentAttr != NULL)
03696         pPressure = m_pParentAttr->GetPressureCache();
03697     
03698     
03699     // initialise members to their starting values
03700     CSampleItem TheItem;
03701     
03702     // our first sample is a short distance in
03703     MILLIPOINT FirstDistance = 10;
03704 
03705     // set the default pressure to normal value
03706     m_CurrentPressure.m_Pressure = MAXPRESSURE / 2;
03707     if (pPressure == NULL)
03708         m_bValidPressure = FALSE;
03709     else
03710     {   
03711         if (pPressure->GetAt(0, &TheItem))
03712         {   
03713             if (TheItem.m_Pressure < 0 || TheItem.m_Pressure > MAXPRESSURE)
03714             {
03715                 ERROR3("Invalid pressure here ");
03716             }
03717             else
03718             {
03719                 m_CurrentPressure.m_Pressure = TheItem.m_Pressure;
03720                 pPressure->SetSampleRateFromSpacing(FirstDistance);
03721             }
03722         }
03723         else
03724             ERROR3("Unable to retrieve first pressure value in PathProcessorBrush::ProcessPath");
03725         
03726         m_bValidPressure = TRUE;
03727     }
03728     return pPressure;
03729 }
03730 
03731 
03732 /********************************************************************************************
03733 
03734 >   CDistanceSampler* PathProcessorBrush::GetPressureCacheAndInitialise(RenderRegion* pRegion, 
03735                                             ValueFunction** ppValFunc)
03736 
03737     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03738     Created:    23/5/2000
03739     Inputs:     pRegion - the render region we are about to render into
03740     Outputs:    ppValFunc - if a non-constant variable width attribute has been rendered into
03741                 pRegion then we return a pointer to it
03742     Returns:    pointer to the pressure data held by our attribute, or NULL if either
03743                 we don't have a pressure cache OR the render region contains a variable width
03744                 attribute with a non-constant value function.
03745 
03746     Purpose:    This should be called to get the pressure cache from the attribute and to 
03747                 set up the relevant members when we wish to start retrieving pressure data
03748                 from the beginning.
03749 
03750                 This overridden version allows us to use applied variable width strokes to 
03751                 provide pressure information instead of the input pressure data.  If we find
03752                 one of these has been rendered into the render region we will use this in preferenve
03753                 to the cache found in the AttrBrushType.
03754 
03755 ********************************************************************************************/
03756 
03757 CDistanceSampler* PathProcessorBrush::GetPressureCacheAndInitialise(RenderRegion* pRegion, ValueFunction** ppValFunc)
03758 {
03759     ERROR2IF(pRegion == NULL, NULL, "Render region is NULL in PathProcessorBrush::GetPressureCacheAndInitialise");
03760 
03761     ValueFunction* pValFunc = NULL;
03762 
03763     // first look for the variable width function
03764     VariableWidthAttrValue *pVarWidthAttr = (VariableWidthAttrValue *) pRegion->GetCurrentAttribute(ATTR_VARWIDTH);
03765     if (pVarWidthAttr != NULL)
03766         pValFunc = pVarWidthAttr->GetWidthFunction();
03767 
03768     
03769     // If it is a constant width stroke, then we ignore it, try to get the cache from the attribute instead
03770     if (pValFunc == NULL || IS_A(pValFunc, ValueFunctionConstant))
03771         return GetPressureCacheAndInitialise();
03772     else
03773     {
03774         // set our starting pressure value
03775 
03776         // set the default pressure to normal value
03777         m_CurrentPressure.m_Pressure = MAXPRESSURE / 2;
03778         
03779         // get the first value out of the value function
03780         double Val = pValFunc->GetValue(0);
03781         
03782         m_CurrentPressure.m_Pressure = (UINT32)((double)MAXPRESSURE * Val);
03783 
03784         // assign it to the output pointer
03785         *ppValFunc = pValFunc;
03786 
03787         m_bValidPressure = TRUE;
03788     }
03789     return NULL;
03790 }
03791 
03792 
03793 /********************************************************************************************
03794 
03795 >   CDistanceSampler* PathProcessorBrush::GetPressureCacheAndInitialise(RenderRegion* pRegion, 
03796                                             ValueFunction** ppValFunc)
03797 
03798     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03799     Created:    23/5/2000
03800     Inputs:     pInkNode - the inknode that hsa this brush applied to it
03801     Outputs:    ppValFunc - if a non-constant variable width attribute is applied to pInkNode then
03802                 we will return a pointer to it
03803 
03804     Returns:    pointer to the pressure data held by our attribute, or NULL if either
03805                 we don't have a pressure cache OR a non-constant VWF is applied to our inknoded
03806 
03807     Purpose:    This should be called to get the pressure cache from the attribute and to 
03808                 set up the relevant members when we wish to start retrieving pressure data
03809                 from the beginning.
03810 
03811                 This overridden version is designed to be use when no render region is available
03812                 but we still need pressure info, for example when calculating bounding boxes
03813                 or DoBecomeA's.   It is a little slower as we have to search for the applied
03814                 attribute.
03815 
03816 ********************************************************************************************/
03817 
03818 CDistanceSampler* PathProcessorBrush::GetPressureCacheAndInitialise(NodeRenderableInk* pInkNode, 
03819                                                                     ValueFunction** ppValFunc)
03820 {
03821     ERROR2IF(pInkNode == NULL, NULL, "Ink node is NULL in PathProcessorBrush::GetPressureCacheAndInitialise");
03822 
03823     ValueFunction* pValFunc = NULL;
03824     AttrVariableWidth* pVarWidth = NULL;
03825     
03826     if (pInkNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrVariableWidth), (NodeAttribute**)&pVarWidth))
03827     {
03828         VariableWidthAttrValue* pVal = (VariableWidthAttrValue*)pVarWidth->GetAttributeValue();
03829         pValFunc = pVal->GetWidthFunction();
03830     }
03831     
03832         // If it is a constant width stroke, then we ignore it, try to get the cache from the attribute instead
03833     if (pValFunc == NULL || IS_A(pValFunc, ValueFunctionConstant))
03834         return GetPressureCacheAndInitialise();
03835     else
03836     {
03837         // set our starting pressure value
03838 
03839         // set the default pressure to normal value
03840         m_CurrentPressure.m_Pressure = MAXPRESSURE / 2;
03841         
03842         // get the first value out of the value function
03843         double Val = pValFunc->GetValue(0);
03844         
03845         m_CurrentPressure.m_Pressure = (UINT32)((double)MAXPRESSURE * Val);
03846 
03847         // assign it to the output pointer
03848         *ppValFunc = pValFunc;
03849 
03850         m_bValidPressure = TRUE;
03851     }
03852 
03853 
03854     return NULL;
03855 }
03856 
03857 
03858 /********************************************************************************************
03859 
03860 >   CSampleItem PathProcessorBrush::GetNextSampleItem(CDistanceSampler* pSampler, ValueFunction* pValFunc, 
03861                                                 double PathProportion = 0)
03862 
03863     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03864     Created:    23/5/2000
03865     Inputs:     pSampler - the pressure cache that we may be using
03866                 pValFunc - the value function that we may be using
03867                 PathProportion - if you are using a value function then you need to provide this
03868     Returns:    The next item to use from either the value function or the cache.  Note that we
03869                 will use the value function in preference to the cache.
03870 
03871     Purpose:    Your one stop shop for getting the next pressure value to use.  Note that we may not
03872                 be using pressure at all in which case all of the inputs will be NULL 
03873 
03874 ********************************************************************************************/
03875 
03876 CSampleItem PathProcessorBrush::GetNextSampleItem(CDistanceSampler* pSampler, ValueFunction* pValFunc, 
03877                                                 double PathProportion)
03878 {
03879     if (PathProportion > 1.0)
03880         PathProportion = 0.98;
03881     if (PathProportion < 0.0)
03882         PathProportion = 0.0;
03883 
03884     // make a default item 
03885     CSampleItem TheItem;
03886     TheItem.m_Pressure = MAXPRESSURE / 2;
03887 
03888     // if we have a value function then use that
03889     if (pValFunc != NULL)
03890     {
03891         double Val = pValFunc->GetValue(PathProportion);
03892         TheItem.m_Pressure = (UINT32)((double)MAXPRESSURE * Val);
03893     //  TRACEUSER( "Diccon", _T("Sample pressure = %d\n"), TheItem.m_Pressure);
03894     }
03895     else if (pSampler != NULL) // otherwise use the sampler
03896     {
03897         pSampler->GetNext(&TheItem);
03898     }
03899 
03900     return TheItem;
03901 }
03902 
03903 
03904 /*------------------------------------------------------------------------------------------
03905 --------------------------------------------------------------------------------------------
03906 ------------------THE DATA ACCESS FUNCTIONS-------------------------------------------------
03907 -------------------------------------------------------------------------------------------*/
03908 
03909 /********************************************************************************************
03910 
03911 >   BOOL PathProcessorBrush::SetBrushSpacing(double Spacing) 
03912 
03913     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03914     Created:    6/10/99
03915     Inputs:     the spacing value to set
03916     Returns:    TRUE if successful, FALSE if the spacing is invalid 
03917     Purpose:    To set the spacing between brush objects
03918     SeeAlso:    -
03919 
03920 ********************************************************************************************/
03921 
03922 BOOL PathProcessorBrush::SetSpacing(MILLIPOINT Spacing)
03923 {
03924     if (Spacing < MIN_BRUSH_SPACING || Spacing > MAX_BRUSH_SPACING)
03925         return FALSE;
03926 
03927     m_BrushSpacing = Spacing;
03928     m_LastSpacing = Spacing;
03929     m_LastSpacingNoRandom = Spacing;
03930 //  TRACEUSER( "Diccon", _T("Spacing Set at %d\n"), m_BrushSpacing);
03931 
03932     return TRUE;
03933 
03934 }
03935 
03936 
03937 
03938 /********************************************************************************************
03939 
03940 >   MILLIPOINT PathProcessorBrush::GetBrushSpacing() 
03941 
03942     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03943     Created:    6/10/99
03944     Returns:    the spacing between the brush objects 
03945     Purpose:    As above
03946 
03947 ********************************************************************************************/
03948 
03949 MILLIPOINT PathProcessorBrush::GetSpacing()
03950 {
03951     return m_BrushSpacing;
03952 }
03953 
03954 
03955 /********************************************************************************************
03956 
03957 >   BOOL PathProcessorBrush::SetSpacingIncrProp(double Incr) 
03958 
03959     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03960     Created:    6/10/99
03961     Inputs:     the spacing increment value to set
03962     Returns:    TRUE if we can draw 10 objects, FALSE if the spacing is invalid 
03963     Purpose:    To set the spacing increment between brush objects
03964     SeeAlso:    -
03965 
03966 ********************************************************************************************/
03967 
03968 BOOL PathProcessorBrush::SetSpacingIncrProp(double Incr)
03969 {
03970     if (Incr <= 0)
03971         return FALSE;
03972 
03973     m_BrushSpacingIncrProp = Incr;
03974     return TRUE;
03975 }
03976 
03977 
03978 
03979 /********************************************************************************************
03980 
03981 >   MILLIPOINT PathProcessorBrush::GetSpacingIncrProp() 
03982 
03983     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
03984     Created:    6/10/99
03985     Returns:    the spacing between the brush objects 
03986     Purpose:    As above
03987 
03988 ********************************************************************************************/
03989 
03990 double PathProcessorBrush::GetSpacingIncrProp()
03991 {
03992     return m_BrushSpacingIncrProp;
03993 }
03994 
03995 
03996 /********************************************************************************************
03997 
03998 >   BOOL PathProcessorBrush::SetSpacingIncrConst(MILLIPOINT Incr) 
03999 
04000     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04001     Created:    6/10/99
04002     Inputs:     the constant spacing increment value to set
04003     Returns:    TRUE if we can draw 10 objects, FALSE if the spacing is invalid 
04004     Purpose:    To set the proportional spacing increment between brush objects
04005     SeeAlso:    -
04006 
04007 ********************************************************************************************/
04008 
04009 BOOL PathProcessorBrush::SetSpacingIncrConst(MILLIPOINT Incr)
04010 {
04011 
04012     m_BrushSpacingIncrConst = Incr;
04013     return TRUE;
04014 }
04015 
04016 
04017 /********************************************************************************************
04018 
04019 >   MILLIPOINT PathProcessorBrush::GetSpacingIncrConst() 
04020 
04021     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04022     Created:    6/10/99
04023     Returns:    the constant spacing increment between the brush objects 
04024     Purpose:    As above
04025 
04026 ********************************************************************************************/
04027 
04028 MILLIPOINT PathProcessorBrush::GetSpacingIncrConst()
04029 {
04030     return m_BrushSpacingIncrConst;
04031 }
04032 
04033 
04034 /********************************************************************************************
04035 
04036 >   UINT32 PathProcessorBrush::GetSpacingMaxRand() 
04037 
04038     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04039     Created:    6/10/99
04040     Returns:    the maximum percentage randomness to be applied to spacing 
04041     Purpose:    As above
04042 
04043 ********************************************************************************************/
04044 
04045 UINT32 PathProcessorBrush::GetSpacingMaxRand()
04046 {
04047     return m_BrushSpacingMaxRand;
04048 }
04049 
04050 
04051 /********************************************************************************************
04052 
04053 >   BOOL PathProcessorBrush::SetSpacingMaxRand(UINT32 Value) 
04054 
04055     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04056     Created:    6/10/99
04057     Inputs::    the maximum percentage randomness to be applied to spacing 
04058     Returns:    TRUE if Value is within the legal limits, otherwise FALSE
04059     Purpose:    As above
04060 
04061 ********************************************************************************************/
04062 
04063 BOOL PathProcessorBrush::SetSpacingMaxRand(UINT32 Value)
04064 {
04065     if (Value < MIN_BRUSH_RAND || Value > MAX_BRUSH_RAND)
04066         return FALSE;
04067     
04068     m_BrushSpacingMaxRand = Value;
04069     return TRUE;
04070 }
04071 
04072 
04073 /********************************************************************************************
04074 
04075 >   UINT32 PathProcessorBrush::GetSpacingRandSeed() 
04076 
04077     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04078     Created:    6/10/99
04079     Returns:    the seed used to determine the sequence of random numbers for spacing
04080     Purpose:    As above
04081 
04082 ********************************************************************************************/
04083 
04084 UINT32 PathProcessorBrush::GetSpacingRandSeed()
04085 {
04086     return m_BrushSpacingRandSeed;
04087 }
04088 
04089 
04090 /********************************************************************************************
04091 
04092 >   BOOL PathProcessorBrush::SetSpacingRandSeed(UINT32 Value) 
04093 
04094     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04095     Created:    6/10/99
04096     Inputs  :   the seed used to determine the sequence of random numbers for spacing
04097     Returns:    TRUE if Value is valid
04098     Purpose:    As above
04099                 
04100 ********************************************************************************************/
04101 
04102 BOOL PathProcessorBrush::SetSpacingRandSeed(UINT32 Value)
04103 {
04104 #ifdef USE_MTRNG
04105     if(m_pSpacingRNG == NULL)
04106     {
04107         m_pSpacingRNG = new MTRand((UINT32)Value);
04108         if (m_pSpacingRNG == NULL)
04109             return FALSE;
04110     }
04111     else
04112         m_pSpacingRNG->seed((UINT32)Value);
04113 #endif
04114     m_BrushSpacingRandSeed = Value;
04115     return TRUE;
04116 }
04117 
04118 
04119 /********************************************************************************************
04120 
04121 >   BOOL PathProcessorBrush::SetSpacingMaxPressure(UINT32 Value) 
04122 
04123     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04124     Created:    6/10/99
04125     Inputs  :   the maximum % effect on spacing that pressure will have
04126     Returns:    TRUE if Value is valid
04127     Purpose:    As above
04128                 
04129 ********************************************************************************************/
04130 
04131 BOOL PathProcessorBrush::SetSpacingMaxPressure(UINT32 Max)
04132 {
04133     if (Max < MIN_PRESSURE_EFFECT || Max > MAX_PRESSURE_EFFECT)
04134         return FALSE;
04135 
04136     m_SpacingMaxPressure = Max;
04137     return TRUE;
04138 }
04139 
04140 
04141 /********************************************************************************************
04142 
04143 >   UINT32 PathProcessorBrush::GetSpacingMaxPressure() 
04144 
04145     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04146     Created:    6/10/99
04147     Inputs  :   -
04148     Returns:    the maximum effect that pressure will have on spacing
04149     Purpose:    As above
04150                 
04151 ********************************************************************************************/
04152 
04153 UINT32 PathProcessorBrush::GetSpacingMaxPressure()
04154 {
04155     return m_SpacingMaxPressure;
04156 }
04157 
04158 
04159 
04160 /********************************************************************************************
04161 
04162 >   MILLIPOINT PathProcessorBrush::GetLastSpacing()
04163 
04164     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04165     Created:    6/10/99
04166     Inputs  :   -
04167     Returns:    the maximum effect that pressure will have on spacing
04168     Purpose:    As above
04169                 
04170 ********************************************************************************************/
04171 
04172 MILLIPOINT PathProcessorBrush::GetLastSpacing()
04173 {
04174     return m_LastSpacing;
04175 }
04176 
04177 /********************************************************************************************
04178 
04179 >   PathOffset PathProcessorBrush::GetPathOffsetType() 
04180 
04181     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04182     Created:    6/10/99
04183     Inputs:     -
04184     Returns:    The type of pathoffset this brush is using 
04185     Purpose:    as above
04186     SeeAlso:    -
04187 
04188 ********************************************************************************************/
04189 
04190 PathOffset PathProcessorBrush::GetPathOffsetType()
04191 {
04192     return m_PathOffsetType;
04193 }
04194 
04195 
04196 
04197 /********************************************************************************************
04198 
04199 >   void PathProcessorBrush::SetPathOffsetType(PathOffset Offset) 
04200 
04201     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04202     Created:    6/10/99
04203     Inputs      Offset - the offset type to set
04204     Returns:    - 
04205     Purpose:    to set the offset type for this brush
04206 ********************************************************************************************/
04207 
04208 void PathProcessorBrush::SetPathOffsetType(PathOffset Offset)
04209 {
04210 #ifdef USE_MTRNG
04211     if (m_pOffsetTypeRNG == NULL)
04212     {
04213         m_pOffsetTypeRNG = new MTRand;
04214         if (m_pOffsetTypeRNG == NULL)
04215             return;
04216     }
04217     m_pOffsetTypeRNG->seed((UINT32)m_OffsetTypeRandSeed);
04218 #endif
04219 
04220     m_PathOffsetType = Offset;
04221 }
04222 
04223 
04224 
04225 /********************************************************************************************
04226 
04227 >   MILLIPOINT PathProcessorBrush::GetPathOffsetValue() 
04228 
04229     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04230     Created:    6/10/99
04231     Inputs:     -
04232     Returns:    The value of the path offset used by this brush 
04233     Purpose:    as above
04234     SeeAlso:    -
04235 
04236 ********************************************************************************************/
04237 
04238 MILLIPOINT PathProcessorBrush::GetPathOffsetValue()
04239 {
04240     return m_PathOffsetValue;
04241 }
04242 
04243 
04244 
04245 /********************************************************************************************
04246 
04247 >   void PathProcessorBrush::SetPathOffsetValue(MILLIPOINT Value) 
04248 
04249     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04250     Created:    6/10/99
04251     Inputs      Value - the offset value to set
04252     Returns:    - 
04253     Purpose:    to set the offset distance for this brush
04254 ********************************************************************************************/
04255 void PathProcessorBrush::SetPathOffsetValue(MILLIPOINT Value)
04256 {
04257     if (Value < 0 || Value > MAX_BRUSH_SPACING)
04258     {
04259     //  ERROR3("invalid offset value");
04260         return;
04261     }
04262 
04263     m_PathOffsetValue = Value;
04264     m_LastOffset = Value;
04265     m_LastOffsetNoRandom  = m_PathOffsetValue;
04266 }
04267 
04268 
04269 /********************************************************************************************
04270 
04271 >   MILLIPOINT PathProcessorBrush::GetPathOffsetIncrConst() 
04272 
04273     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04274     Created:    6/10/99
04275     Inputs:     -
04276     Returns:    The value of the constant path offset increment used by this brush 
04277     Purpose:    as above
04278     SeeAlso:    -
04279 
04280 ********************************************************************************************/
04281 
04282 MILLIPOINT PathProcessorBrush::GetPathOffsetIncrConst()
04283 {
04284     return m_PathOffsetIncrConst;
04285 }
04286 
04287 
04288 
04289 /********************************************************************************************
04290 
04291 >   BOOL PathProcessorBrush::SetPathOffsetIncrConst(MILLIPOINT Value) 
04292 
04293     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04294     Created:    6/10/99
04295     Inputs      Value - the offset increment value to set
04296     Returns:    - 
04297     Purpose:    to set the offset distance for this brush
04298 ********************************************************************************************/
04299 BOOL PathProcessorBrush::SetPathOffsetIncrConst(MILLIPOINT Value)
04300 {
04301     m_PathOffsetIncrConst = Value;
04302     return TRUE;
04303 }
04304 
04305 
04306 /********************************************************************************************
04307 
04308 >   double PathProcessorBrush::GetPathOffsetIncrProp() 
04309 
04310     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04311     Created:    6/10/99
04312     Inputs:     -
04313     Returns:    The value of the proportional path offset increment used by this brush 
04314     Purpose:    as above
04315     SeeAlso:    -
04316 
04317 ********************************************************************************************/
04318 
04319 double PathProcessorBrush::GetPathOffsetIncrProp()
04320 {
04321     return m_PathOffsetIncrProp;
04322 }
04323 
04324 
04325 
04326 /********************************************************************************************
04327 
04328 >   BOOL PathProcessorBrush::SetPathOffsetIncrProp(double Incr) 
04329 
04330     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04331     Created:    6/10/99
04332     Inputs      incr - the proportional offset increment value to set
04333     Returns:    - 
04334     Purpose:    to set the offset distance for this brush
04335 ********************************************************************************************/
04336 BOOL PathProcessorBrush::SetPathOffsetIncrProp(double Incr)
04337 {
04338     if (Incr <= 0 )
04339         return FALSE;
04340     // test to see if 10 objects takes us to the limit
04341     // Don't do this anymore, as we limit our spacing at render-time
04342 /*  double TenIncr = pow(Incr, 10.0);
04343     if ((m_PathOffsetValue * TenIncr) >= MAX_BRUSH_SPACING)
04344         return FALSE;
04345 */
04346     m_PathOffsetIncrProp = Incr;
04347     return TRUE;
04348 }
04349 
04350 
04351 /********************************************************************************************
04352 
04353 >   UINT32 PathProcessorBrush::GetOffsetValueMaxRand() 
04354 
04355     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04356     Created:    6/10/99
04357     Returns:    the maximum percentage randomness to be applied to Offset
04358     Purpose:    As above
04359 
04360 ********************************************************************************************/
04361 
04362 UINT32 PathProcessorBrush::GetOffsetValueMaxRand()
04363 {
04364     return m_OffsetValueMaxRand;
04365 }
04366 
04367 
04368 /********************************************************************************************
04369 
04370 >   BOOL PathProcessorBrush::SetOffsetValueMaxRand(UINT32 Value) 
04371 
04372     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04373     Created:    6/10/99
04374     Inputs::    the maximum percentage randomness to be applied to Offset
04375     Returns:    TRUE if Value is within the legal limits, otherwise FALSE
04376     Purpose:    As above
04377 
04378 ********************************************************************************************/
04379 
04380 BOOL PathProcessorBrush::SetOffsetValueMaxRand(UINT32 Value)
04381 {
04382     if (Value < MIN_BRUSH_RAND || Value > MAX_BRUSH_RAND)
04383         return FALSE;
04384     
04385     m_OffsetValueMaxRand = Value;
04386     return TRUE;
04387 }
04388 
04389 
04390 /********************************************************************************************
04391 
04392 >   UINT32 PathProcessorBrush::GetOffsetValueRandSeed() 
04393 
04394     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04395     Created:    6/10/99
04396     Returns:    the seed used to determine the sequence of random numbers for offset value
04397     Purpose:    As above
04398 
04399 ********************************************************************************************/
04400 
04401 UINT32 PathProcessorBrush::GetOffsetValueRandSeed()
04402 {
04403     return m_OffsetValueRandSeed;
04404 }
04405 
04406 
04407 /********************************************************************************************
04408 
04409 >   BOOL PathProcessorBrush::SetOffsetValueRandSeed(UINT32 Value) 
04410 
04411     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04412     Created:    6/10/9
04413     Inputs  :   the seed used to determine the sequence of random numbers for offset value
04414     Returns:    TRUE if Value is valid, which it always is at the moment
04415     Purpose:    As above
04416                 
04417 ********************************************************************************************/
04418 
04419 BOOL PathProcessorBrush::SetOffsetValueRandSeed(UINT32 Value)
04420 {
04421 #ifdef USE_MTRNG
04422     if(m_pOffsetValueRNG == NULL)
04423     {
04424         m_pOffsetValueRNG = new MTRand((UINT32)Value);
04425         if (m_pOffsetValueRNG == NULL)
04426             return FALSE;
04427     }
04428     else
04429         m_pOffsetValueRNG->seed((UINT32)Value);
04430 #endif
04431     m_OffsetValueRandSeed = Value;
04432     return TRUE;
04433 
04434 }
04435 
04436 
04437 
04438 
04439 
04440 /********************************************************************************************
04441 
04442 >   UINT32 PathProcessorBrush::GetOffsetTypeRandSeed() 
04443 
04444     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04445     Created:    6/10/99
04446     Returns:    the seed used to determine the sequence of random numbers for offset value
04447     Purpose:    As above
04448 
04449 ********************************************************************************************/
04450 
04451 UINT32 PathProcessorBrush::GetOffsetTypeRandSeed()
04452 {
04453     return m_OffsetTypeRandSeed;
04454 }
04455 
04456 
04457 /********************************************************************************************
04458 
04459 >   BOOL PathProcessorBrush::SetOffsetTypeRandSeed(UINT32 Value) 
04460 
04461     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04462     Created:    6/10/9
04463     Inputs  :   the seed used to determine the sequence of random numbers for offset value
04464     Returns:    TRUE if Value is valid, which it always is at the moment
04465     Purpose:    As above
04466                 
04467 ********************************************************************************************/
04468 BOOL PathProcessorBrush::SetOffsetTypeRandSeed(UINT32 Value)
04469 {
04470 #ifdef USE_MTRNG
04471     if(m_pOffsetTypeRNG == NULL)
04472     {
04473         m_pOffsetTypeRNG = new MTRand((UINT32)Value);
04474         if (m_pOffsetTypeRNG == NULL)
04475             return FALSE;
04476     }
04477     else
04478         m_pOffsetTypeRNG->seed((UINT32)Value);
04479 #endif
04480 
04481     m_OffsetTypeRandSeed = Value;
04482     return TRUE;
04483 
04484 }
04485 
04486 /********************************************************************************************
04487 
04488 >   void PathProcessorBrush::SetTiling(BOOL Value) 
04489 
04490     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04491     Created:    6/10/99
04492     Inputs:     whether or not the brush tiles
04493     Returns:    -
04494     Purpose:    When a brush tiles it means that the attribute types:
04495                 - 3 colour fill
04496                 - 4 colour fill
04497                 - bitmap fill
04498                 are only rendered once per brush, rather than for every brush step
04499     SeeAlso:    -
04500 
04501 ********************************************************************************************/
04502 
04503 void PathProcessorBrush::SetTiling(BOOL Value)
04504 {
04505     m_bTile = Value;
04506 }
04507 
04508 
04509 
04510 /********************************************************************************************
04511 
04512 >   BOOL PathProcessorBrush::GetTiling() 
04513 
04514     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04515     Created:    6/10/99
04516     Inputs:     
04517     Returns:    whether or not the brush tiles
04518     Purpose:    as above
04519     SeeAlso:    -
04520 
04521 ********************************************************************************************/
04522 
04523 BOOL PathProcessorBrush::IsTiled()
04524 {
04525     return m_bTile;
04526 }
04527 
04528 
04529 
04530 /********************************************************************************************
04531 
04532 >   BOOL PathProcessorBrush::SetRotationAngle(double Angle) 
04533 
04534     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04535     Created:    6/10/99
04536     Inputs:     the angle of rotation to set
04537     Returns:    TRUE if the angle is within the stated bounds
04538     Purpose:    as above
04539     SeeAlso:    -
04540 
04541 ********************************************************************************************/
04542 
04543 BOOL PathProcessorBrush::SetRotationAngle(double Angle)
04544 {
04545     /*if (Angle <= MIN_ANGLE || Angle >= MAX_ANGLE)
04546     {
04547         ERROR3("Invalid angle");
04548         return FALSE;
04549     
04550     }*/
04551     m_RotateAngle = Angle;
04552     m_LastAngle   = m_RotateAngle;
04553     m_LastRotationNoRandom = m_RotateAngle;
04554     return TRUE;
04555 }
04556 
04557 /********************************************************************************************
04558 
04559 >   double PathProcessorBrush::GetRotationAngle() 
04560 
04561     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04562     Created:    6/10/99
04563     Inputs:     -
04564     Returns:    the angle of rotation that has been set
04565     Purpose:    as above
04566     SeeAlso:    -
04567 
04568 ********************************************************************************************/
04569 
04570 double PathProcessorBrush::GetRotationAngle()
04571 {
04572     return m_RotateAngle;
04573 }
04574 
04575 
04576 /********************************************************************************************
04577 
04578 >   BOOL PathProcessorBrush::SetRotAngleIncrConst(double Angle) 
04579 
04580     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04581     Created:    6/10/99
04582     Inputs:     the incremental angle of rotation to set
04583     Returns:    TRUE if the angle is within the stated bounds
04584     Purpose:    as above
04585     SeeAlso:    -
04586 
04587 ********************************************************************************************/
04588 
04589 BOOL PathProcessorBrush::SetRotationIncrConst(double Angle)
04590 {
04591     m_RotAngleIncrConst = Angle;
04592 
04593     return TRUE;
04594 }
04595 
04596 /********************************************************************************************
04597 
04598 >   double PathProcessorBrush::GetRotAngleIncrConst() 
04599 
04600     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04601     Created:    6/10/99
04602     Inputs:     -
04603     Returns:    the increment to the angle of rotation 
04604     Purpose:    as above
04605     SeeAlso:    -
04606 
04607 ********************************************************************************************/
04608 
04609 double PathProcessorBrush::GetRotationIncrConst()
04610 {
04611     return m_RotAngleIncrConst;
04612 }
04613 
04614 
04615 /********************************************************************************************
04616 
04617 >   BOOL PathProcessorBrush::SetRotAngleIncrProp(double Angle) 
04618 
04619     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04620     Created:    6/10/99
04621     Inputs:     the incremental angle of rotation to set
04622     Returns:    TRUE if the angle is within the stated bounds
04623     Purpose:    as above
04624     SeeAlso:    -
04625 
04626 ********************************************************************************************/
04627 
04628 BOOL PathProcessorBrush::SetRotationIncrProp(double Value)
04629 {
04630     m_RotAngleIncrProp = Value;
04631 
04632     return TRUE;
04633 }
04634 
04635 /********************************************************************************************
04636 
04637 >   double PathProcessorBrush::GetRotAngleIncrProp() 
04638 
04639     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04640     Created:    6/10/99
04641     Inputs:     -
04642     Returns:    the increment to the angle of rotation 
04643     Purpose:    as above
04644     SeeAlso:    -
04645 
04646 ********************************************************************************************/
04647 
04648 double PathProcessorBrush::GetRotationIncrProp()
04649 {
04650     return m_RotAngleIncrProp;
04651 }
04652 
04653 /********************************************************************************************
04654 
04655 >   UINT32 PathProcessorBrush::GetRotationMaxRand() 
04656 
04657     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04658     Created:    6/10/99
04659     Inputs:     -
04660     Returns:    the maximum amount of randomness to be applied to the rotation angle
04661     Purpose:    as above
04662     SeeAlso:    -
04663 
04664 ********************************************************************************************/
04665 
04666 UINT32 PathProcessorBrush::GetRotationMaxRand()
04667 {
04668     return m_RotationMaxRand;
04669 }
04670 
04671 
04672 /********************************************************************************************
04673 
04674 >   BOOL PathProcessorBrush::SetRotationMaxRand(UINT32 Value) 
04675 
04676     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04677     Created:    6/10/99
04678     Inputs:     the maximum amount of randomness (as a %) to be applied to rotation
04679     Returns:    -
04680     Purpose:    as above
04681     SeeAlso:    -
04682 
04683 ********************************************************************************************/
04684 
04685 BOOL PathProcessorBrush::SetRotationMaxRand(UINT32 Value)
04686 {
04687     m_RotationMaxRand = Value;
04688     return TRUE;
04689 }
04690 
04691 
04692 /********************************************************************************************
04693 
04694 >   UINT32 PathProcessorBrush::GetRotationRandSeed() 
04695 
04696     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04697     Created:    6/10/99
04698     Inputs:     -
04699     Returns:    the  seed to use to generate the  rotation RNG
04700     Purpose:    as above
04701     SeeAlso:    -
04702 
04703 ********************************************************************************************/
04704 
04705 UINT32 PathProcessorBrush::GetRotationRandSeed()
04706 {
04707     return m_RotationRandSeed;
04708 }
04709 
04710 
04711 
04712 /********************************************************************************************
04713 
04714 >   BOOL PathProcessorBrush::SetRotationRandSeed(UINT32 Seed) 
04715 
04716     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04717     Created:    6/10/99
04718     Inputs:     the seed to use
04719     Returns:    -
04720     Purpose:    as above
04721     SeeAlso:    -
04722 
04723 ********************************************************************************************/
04724 
04725 void PathProcessorBrush::SetRotationRandSeed(UINT32 Seed)
04726 {
04727 #ifdef USE_MTRNG
04728     if (m_pRotationRNG == NULL)
04729     {
04730         m_pRotationRNG = new MTRand;
04731         if (m_pRotationRNG == NULL)
04732             return;
04733     }
04734     m_pRotationRNG->seed((UINT32)Seed);
04735 #endif
04736     m_RotationRandSeed = Seed;
04737 }
04738 
04739 
04740 
04741 /********************************************************************************************
04742 
04743 >   UINT32 PathProcessorBrush::GetRotationMaxPressure() 
04744 
04745     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04746     Created:    6/10/99
04747     Inputs:     -
04748     Returns:    the  seed to use to generate the  rotation RNG
04749     Purpose:    as above
04750     SeeAlso:    -
04751 
04752 ********************************************************************************************/
04753 
04754 UINT32 PathProcessorBrush::GetRotationMaxPressure()
04755 {
04756     return m_RotationMaxPressure;
04757 }
04758 
04759 
04760 
04761 /********************************************************************************************
04762 
04763 >   BOOL PathProcessorBrush::SetRotationMaxPressure(UINT32 Seed) 
04764 
04765     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04766     Created:    6/10/99
04767     Inputs:     the seed to use
04768     Returns:    -
04769     Purpose:    as above
04770     SeeAlso:    -
04771 
04772 ********************************************************************************************/
04773 
04774 BOOL PathProcessorBrush::SetRotationMaxPressure(UINT32 Value)
04775 {
04776     if (Value < MIN_PRESSURE_EFFECT || Value > MAX_PRESSURE_EFFECT)
04777         return FALSE;
04778     m_RotationMaxPressure = Value;
04779     return TRUE;
04780 }
04781 
04782 /********************************************************************************************
04783 
04784 >   BOOL PathProcessorBrush::IsRotated() 
04785 
04786     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04787     Created:    6/10/99
04788     Inputs:     
04789     Returns:    whether or not the brush objects are rotated
04790     Purpose:    as above
04791     SeeAlso:    -
04792 
04793 ********************************************************************************************/
04794 
04795 BOOL PathProcessorBrush::IsRotated()
04796 {
04797     return m_bRotate;
04798 }
04799 
04800 
04801 /********************************************************************************************
04802 
04803 >   void PathProcessorBrush::SetRotation(BOOL Value) 
04804 
04805     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04806     Created:    6/10/99
04807     Inputs:     whether or not the brush rotates
04808     Returns:    -
04809     Purpose:    as above
04810     SeeAlso:    -
04811 
04812 ********************************************************************************************/
04813 
04814 void PathProcessorBrush::SetRotated(BOOL Value)
04815 {
04816     m_bRotate = Value;
04817 }
04818 
04819 
04820 /********************************************************************************************
04821 
04822 >   double PathProcessorBrush::GetBrushScaling() 
04823 
04824     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04825     Created:    6/10/99
04826     Inputs:     -
04827     Returns:    the scaling factor to use when drawing the objects
04828     Purpose:    as above
04829     SeeAlso:    -
04830 
04831 ********************************************************************************************/
04832 
04833 double PathProcessorBrush::GetBrushScaling()
04834 {
04835     return m_BrushScaling;
04836 }
04837 
04838 
04839 
04840 /********************************************************************************************
04841 
04842 >   bool PathProcessorBrush::SetScaling(double Scale) 
04843 
04844     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04845     Created:    6/10/99
04846     Inputs:     the scale factor to set
04847     Returns:    TRUE if Scale is within the permitted bounds
04848     Purpose:    to set the member that determine to what scale of the original object each 
04849                 brush object is drawn
04850     SeeAlso:    -
04851 
04852 ********************************************************************************************/
04853 
04854 BOOL PathProcessorBrush::SetBrushScaling(double Scale)
04855 {
04856     /*if (Scale <= MIN_BRUSH_SCALE )
04857     {
04858         //InformError(_R(IDS_BRUSH_SCALE_TOOSMALL));
04859         m_BrushScaling = MIN_BRUSH_SCALE;
04860         return TRUE;
04861     }
04862     else*/ if (Scale >= MAX_BRUSH_SCALE)
04863     {
04864         //InformError(_R(IDS_BRUSH_SCALE_TOOBIG));
04865         m_BrushScaling = MAX_BRUSH_SCALE;
04866         return TRUE;
04867     }
04868     
04869     m_BrushScaling = Scale;
04870     m_CurrentScaling = Scale;
04871     m_LastScaling = Scale;
04872     m_LastScalingNoRandom = Scale;
04873     return TRUE;
04874 }
04875 
04876 
04877 /********************************************************************************************
04878 
04879 >   double PathProcessorBrush::GetBrushScalingIncr() 
04880 
04881     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04882     Created:    6/10/99
04883     Inputs:     -
04884     Returns:    the scaling factor increment to use when drawing the objects
04885     Purpose:    as above
04886     SeeAlso:    -
04887 
04888 ********************************************************************************************/
04889 
04890 double PathProcessorBrush::GetBrushScalingIncr()
04891 {
04892     return m_BrushScalingIncr;
04893 }
04894 
04895 
04896 
04897 /********************************************************************************************
04898 
04899 >   bool PathProcessorBrush::SetBrushScalingincr(double incr) 
04900 
04901     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04902     Created:    6/10/99
04903     Inputs:     the scale factor increment to set
04904     Returns:    TRUE if the increment allows 10 objects to be drawn 
04905     Purpose:    to set the member that determine the increment to scaling applied
04906                 to each brush object
04907                 Note that the scaling MUST be set before this is called
04908     SeeAlso:    -
04909 
04910 ********************************************************************************************/
04911 
04912 BOOL PathProcessorBrush::SetBrushScalingIncr(double Incr)
04913 {
04914     if (Incr <= 0)
04915     {
04916         //ERROR3("Negative scaling increment");
04917         return FALSE;
04918     }
04919 
04920     m_BrushScalingIncr = Incr;
04921     return TRUE;
04922 }
04923 
04924 
04925 /********************************************************************************************
04926 
04927 >   double PathProcessorBrush::GetBrushScalingIncrConst() 
04928 
04929     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04930     Created:    6/10/99
04931     Inputs:     -
04932     Returns:    the scaling factor increment to use when drawing the objects
04933     Purpose:    as above
04934     SeeAlso:    -
04935 
04936 ********************************************************************************************/
04937 
04938 double PathProcessorBrush::GetBrushScalingIncrConst()
04939 {
04940     return m_BrushScalingIncrConst;
04941 }
04942 
04943 /********************************************************************************************
04944 
04945 >   bool PathProcessorBrush::SetBrushScalingincrConst(double Incr) 
04946 
04947     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04948     Created:    6/10/99
04949     Inputs:     the scale factor increment to set
04950     Returns:    TRUE unless Incr >= 100
04951     Purpose:    to set the member that determine the increment to scaling applied
04952                 to each brush object
04953                 
04954     SeeAlso:    -
04955 
04956 ********************************************************************************************/
04957 
04958 BOOL PathProcessorBrush::SetBrushScalingIncrConst(double Incr)
04959 {
04960     if (Abs(Incr) >= 100)
04961     {
04962         return FALSE;
04963     }
04964     m_BrushScalingIncrConst = Incr;
04965     return TRUE;
04966 }
04967 
04968 /********************************************************************************************
04969 
04970 >   UINT32 PathProcessorBrush::GetScalingMaxRand() 
04971 
04972     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04973     Created:    6/10/99
04974     Returns:    the maximum percentage randomness to be applied to Scaling 
04975     Purpose:    As above
04976 
04977 ********************************************************************************************/
04978 
04979 UINT32 PathProcessorBrush::GetScalingMaxRand()
04980 {
04981     return m_BrushScalingMaxRand;
04982 }
04983 
04984 
04985 /********************************************************************************************
04986 
04987 >   BOOL PathProcessorBrush::SetScalingMaxRand(UINT32 Value) 
04988 
04989     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04990     Created:    6/10/99
04991     Inputs::    the maximum percentage randomness to be applied to Scaling 
04992     Returns:    TRUE if Value is within the legal limits, otherwise FALSE
04993     Purpose:    As above
04994 
04995 ********************************************************************************************/
04996 
04997 BOOL PathProcessorBrush::SetScalingMaxRand(UINT32 Value)
04998 {
04999     if (Value < MIN_BRUSH_RAND || Value > MAX_BRUSH_RAND)
05000         return FALSE;
05001     
05002     m_BrushScalingMaxRand = Value;
05003     return TRUE;
05004 }
05005 
05006 
05007 /********************************************************************************************
05008 
05009 >   UINT32 PathProcessorBrush::GetScalingRandSeed() 
05010 
05011     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05012     Created:    6/10/99
05013     Returns:    the seed used to determine the sequence of random numbers for Scaling
05014     Purpose:    As above
05015 
05016 ********************************************************************************************/
05017 
05018 UINT32 PathProcessorBrush::GetScalingRandSeed()
05019 {
05020     return m_BrushScalingRandSeed;
05021 }
05022 
05023 
05024 /********************************************************************************************
05025 
05026 >   BOOL PathProcessorBrush::SetScalingRandSeed(UINT32 Value) 
05027 
05028     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05029     Created:    6/10/99
05030     Inputs  :   the seed used to determine the sequence of random numbers for spacing
05031     Returns:    TRUE if Value is valid, which it always is at the moment
05032     Purpose:    As above
05033                 
05034 ********************************************************************************************/
05035 
05036 BOOL PathProcessorBrush::SetScalingRandSeed(UINT32 Value)
05037 {
05038 #ifdef USE_MTRNG
05039     if(m_pScalingRNG == NULL)
05040     {
05041         m_pScalingRNG = new MTRand((UINT32)Value);
05042         if (m_pScalingRNG == NULL)
05043             return FALSE;
05044     }
05045     else
05046         m_pScalingRNG->seed((UINT32)Value);
05047 #endif
05048     m_BrushScalingRandSeed = Value;
05049     return TRUE;
05050 }
05051 
05052 
05053 /********************************************************************************************
05054 
05055 >   UINT32 PathProcessorBrush::GetScalingMaxPressure() 
05056 
05057     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05058     Created:    6/10/99
05059     Returns:    the maximum percentage effect that pressure will have on Scaling 
05060     Purpose:    As above
05061 
05062 ********************************************************************************************/
05063 
05064 UINT32 PathProcessorBrush::GetScalingMaxPressure()
05065 {
05066     return m_ScalingMaxPressure;
05067 }
05068 
05069 
05070 /********************************************************************************************
05071 
05072 >   double PathProcessorBrush::GetLastScaling()
05073 
05074     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05075     Created:    6/10/99
05076     Returns:    the last scaling value that was generated
05077     Purpose:    As above
05078 
05079 ********************************************************************************************/
05080 
05081 double PathProcessorBrush::GetLastScaling()
05082 {
05083     return m_LastScaling;
05084 }
05085 
05086 /********************************************************************************************
05087 
05088 >   BOOL PathProcessorBrush::SetScalingMaxPressure(UINT32 Pressure) 
05089 
05090     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05091     Created:    6/10/99
05092     Inputs:     the maximum percentage effect that pressure will have on Scaling 
05093     Returns:    -
05094     Purpose:    As above
05095 
05096 ********************************************************************************************/
05097 
05098 BOOL PathProcessorBrush::SetScalingMaxPressure(UINT32 Max)
05099 {
05100     if (Max < MIN_PRESSURE_EFFECT || Max > MAX_PRESSURE_EFFECT)
05101         return FALSE;
05102     m_ScalingMaxPressure = Max;
05103     return TRUE;
05104 }
05105 
05106 
05107 /********************************************************************************************
05108 
05109 >   double PathProcessorBrush::GetHueIncrement()
05110 
05111     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05112     Created:    6/10/99
05113     Inputs:     -
05114     Returns:    the hue increment for this brush
05115     Purpose:    as above
05116     SeeAlso:    -
05117 
05118 ********************************************************************************************/
05119 
05120 double PathProcessorBrush::GetHueIncrement()
05121 {
05122     return m_BrushHueIncrement;
05123 }
05124 
05125 
05126 /********************************************************************************************
05127 
05128 >   double PathProcessorBrush::GetHueIncrement()
05129 
05130     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05131     Created:    6/10/99
05132     Inputs:     the hue increment for this brush
05133     Returns:    -
05134     Purpose:    as above
05135     SeeAlso:    -
05136 
05137 ********************************************************************************************/
05138 
05139 BOOL PathProcessorBrush::SetHueIncrement(double Incr)
05140 {
05141     m_BrushHueIncrement = Incr;
05142     return TRUE;
05143 }
05144 
05145 
05146 /********************************************************************************************
05147 
05148 >   UINT32 PathProcessorBrush::GetHueMaxRand()
05149 
05150     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05151     Created:    6/10/99
05152     Inputs:     -
05153     Returns:    the hue increment random amount for this brush
05154     Purpose:    as above
05155     SeeAlso:    -
05156 
05157 ********************************************************************************************/
05158 
05159 UINT32 PathProcessorBrush::GetHueMaxRand()
05160 {
05161     return m_BrushHueMaxRand;
05162 }
05163 
05164 
05165 
05166 /********************************************************************************************
05167 
05168 >   BOOL PathProcessorBrush::SetHueMaxRand(UINT32 Rand)
05169 
05170     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05171     Created:    6/10/99
05172     Inputs:     the hue increment random amount for this brush
05173     Returns:    -
05174     Purpose:    as above
05175     SeeAlso:    -
05176 
05177 ********************************************************************************************/
05178 
05179 BOOL PathProcessorBrush::SetHueMaxRand(UINT32 Rand)
05180 {
05181     m_BrushHueMaxRand = Rand;
05182     return TRUE;
05183 }
05184 
05185 
05186 /********************************************************************************************
05187 
05188 >   UINT32 PathProcessorBrush::GetHueRandSeed()
05189 
05190     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05191     Created:    6/10/99
05192     Inputs:     -
05193     Returns:    the hue increment random amount for this brush
05194     Purpose:    as above
05195     SeeAlso:    -
05196 
05197 ********************************************************************************************/
05198 
05199 UINT32 PathProcessorBrush::GetHueRandSeed()
05200 {
05201     return m_BrushHueRandSeed;
05202 }
05203 
05204 
05205 
05206 /********************************************************************************************
05207 
05208 >   BOOL PathProcessorBrush::SetHueRandSeed(UINT32 Rand)
05209 
05210     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05211     Created:    6/10/99
05212     Inputs:     the hue increment random amount for this brush
05213     Returns:    -
05214     Purpose:    as above
05215     SeeAlso:    -
05216 
05217 ********************************************************************************************/
05218 
05219 BOOL PathProcessorBrush::SetHueRandSeed(UINT32 Rand)
05220 {
05221     m_BrushHueRandSeed = Rand;
05222     
05223 #ifdef USE_MTRNG
05224     if(m_pHueRNG == NULL)
05225     {
05226         m_pHueRNG = new MTRand((UINT32)Rand);
05227         if (m_pHueRNG == NULL)
05228             return FALSE;
05229     }
05230     else
05231         m_pHueRNG->seed((UINT32)Rand);
05232 #endif
05233     return TRUE;
05234 }
05235 
05236 
05237 /********************************************************************************************
05238 
05239 >   double PathProcessorBrush::GetSatIncrement()
05240 
05241     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05242     Created:    6/10/99
05243     Inputs:     -
05244     Returns:    the Saturation increment for this brush
05245     Purpose:    as above
05246     SeeAlso:    -
05247 
05248 ********************************************************************************************/
05249 
05250 double PathProcessorBrush::GetSatIncrement()
05251 {
05252     return m_BrushSatIncrement;
05253 }
05254 
05255 
05256 /********************************************************************************************
05257 
05258 >   double PathProcessorBrush::GetSatIncrement()
05259 
05260     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05261     Created:    6/10/99
05262     Inputs:     the Saturation increment for this brush
05263     Returns:    -
05264     Purpose:    as above
05265     SeeAlso:    -
05266 
05267 ********************************************************************************************/
05268 
05269 BOOL PathProcessorBrush::SetSatIncrement(double Incr)
05270 {
05271     m_BrushSatIncrement = Incr;
05272     return TRUE;
05273 }
05274 
05275 
05276 /********************************************************************************************
05277 
05278 >   UINT32 PathProcessorBrush::GetSatMaxRand()
05279 
05280     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05281     Created:    6/10/99
05282     Inputs:     -
05283     Returns:    the Saturation increment random amount for this brush
05284     Purpose:    as above
05285     SeeAlso:    -
05286 
05287 ********************************************************************************************/
05288 
05289 UINT32 PathProcessorBrush::GetSatMaxRand()
05290 {
05291     return m_BrushSatMaxRand;
05292 }
05293 
05294 
05295 
05296 /********************************************************************************************
05297 
05298 >   BOOL PathProcessorBrush::SetSatMaxRand(UINT32 Rand)
05299 
05300     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05301     Created:    6/10/99
05302     Inputs:     the Saturation increment random amount for this brush
05303     Returns:    -
05304     Purpose:    as above
05305     SeeAlso:    -
05306 
05307 ********************************************************************************************/
05308 
05309 BOOL PathProcessorBrush::SetSatMaxRand(UINT32 Rand)
05310 {
05311     m_BrushSatMaxRand = Rand;
05312     return TRUE;
05313 }
05314 
05315 
05316 /********************************************************************************************
05317 
05318 >   UINT32 PathProcessorBrush::GetSatRandSeed()
05319 
05320     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05321     Created:    6/10/99
05322     Inputs:     -
05323     Returns:    the Saturation increment random amount for this brush
05324     Purpose:    as above
05325     SeeAlso:    -
05326 
05327 ********************************************************************************************/
05328 
05329 UINT32 PathProcessorBrush::GetSatRandSeed()
05330 {
05331     return m_BrushSatRandSeed;
05332 }
05333 
05334 
05335 
05336 /********************************************************************************************
05337 
05338 >   BOOL PathProcessorBrush::SetSatRandSeed(UINT32 Rand)
05339 
05340     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05341     Created:    6/10/99
05342     Inputs:     the Saturation increment random amount for this brush
05343     Returns:    -
05344     Purpose:    as above
05345     SeeAlso:    -
05346 
05347 ********************************************************************************************/
05348 
05349 BOOL PathProcessorBrush::SetSatRandSeed(UINT32 Rand)
05350 {
05351     m_BrushSatRandSeed = Rand;
05352 
05353 #ifdef USE_MTRNG
05354     if(m_pSaturationRNG == NULL)
05355     {
05356         m_pSaturationRNG = new MTRand((UINT32)Rand);
05357         if (m_pSaturationRNG == NULL)
05358             return FALSE;
05359     }
05360     else
05361         m_pSaturationRNG->seed((UINT32)Rand);
05362 #endif
05363     return TRUE;
05364 }
05365 
05366 /********************************************************************************************
05367 
05368 >   SequenceType PathProcessorBrush::GetSequenceType() 
05369 
05370     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05371     Created:    6/10/99
05372     Inputs:     -
05373     Returns:    the type of sequence we are using for mutliple ink objects
05374     Purpose:    as above
05375     SeeAlso:    -
05376 
05377 ********************************************************************************************/
05378 
05379 SequenceType PathProcessorBrush::GetSequenceType()
05380 {
05381     return m_SequenceType;
05382 }
05383 
05384 
05385 /********************************************************************************************
05386 
05387 >   void PathProcessorBrush::SetSequenceType(SequenceType Type) 
05388 
05389     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05390     Created:    6/10/99
05391     Inputs:     the type of sequence to use
05392     Returns:    -
05393     Purpose:    as above
05394     SeeAlso:    -
05395 
05396 ********************************************************************************************/
05397 
05398 void PathProcessorBrush::SetSequenceType(SequenceType Type)
05399 {
05400     m_SequenceType = Type;
05401     if (Type == SEQ_MIRROR)
05402         m_MirrorSeqAscend = TRUE;
05403 
05404     // if we're going random then initialise the RNG
05405     if (m_SequenceType == SEQ_RANDOM)
05406         SetSequenceSeed(m_SequenceRandSeed);
05407 }
05408 
05409 
05410 /********************************************************************************************
05411 
05412 >   void PathProcessorBrush::SetSequenceSeed(UINT32 Seed) 
05413 
05414     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05415     Created:    6/10/99
05416     Inputs:     the random seed to use for sequences
05417     Returns:    -
05418     Purpose:    as above
05419     SeeAlso:    -
05420 
05421 ********************************************************************************************/
05422 
05423 void PathProcessorBrush::SetSequenceSeed(UINT32 Seed)
05424 {
05425     m_SequenceRandSeed = Seed;
05426     if (m_SequenceType == SEQ_RANDOM)
05427     {
05428 #ifdef USE_MTRNG
05429         if (m_pSequenceRNG == NULL)
05430         {
05431             m_pSequenceRNG = new MTRand;
05432             if (m_pSequenceRNG == NULL)
05433                 return;
05434         }
05435         m_pSequenceRNG->seed((UINT32)Seed);
05436     }
05437 #endif
05438 
05439     
05440 }
05441 
05442 
05443 /********************************************************************************************
05444 
05445 >   UINT32 PathProcessorBrush::GetSequenceSeed) 
05446 
05447     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05448     Created:    6/10/99
05449     Inputs:     -
05450     Returns:    the seed we are using to generate random sequences
05451     Purpose:    as above
05452     SeeAlso:    -
05453 
05454 ********************************************************************************************/
05455 
05456 UINT32 PathProcessorBrush::GetSequenceSeed()
05457 {
05458     return m_SequenceRandSeed;
05459 }
05460 
05461 
05462 
05463 
05464 /********************************************************************************************
05465 
05466 >   UINT32 PathProcessorBrush::GetNumBrushObjects() 
05467 
05468     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05469     Created:    6/10/99
05470     Inputs:     -
05471     Returns:    the number of objects used by our brush definition, or zero if something goes wrong
05472     Purpose:    as above
05473     SeeAlso:    -
05474 
05475 ********************************************************************************************/
05476 
05477 UINT32 PathProcessorBrush::GetNumBrushObjects()
05478 {
05479     BrushDefinition* pBrushDef = GetOurBrushDefinition();
05480     if (pBrushDef == NULL)
05481         return 0;
05482     return pBrushDef->GetNumBrushObjects();
05483 }
05484 
05485 
05486 /********************************************************************************************
05487 
05488 >   BOOL PathProcessorBrush::GetUseLocalFillColour() 
05489 
05490     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05491     Created:    6/10/99
05492     Inputs:     -
05493     Returns:    the flag saying whether or not to use our local fill when rendering
05494     Purpose:    as above
05495     SeeAlso:    -
05496 
05497 ********************************************************************************************/
05498 
05499 BOOL PathProcessorBrush::GetUseLocalFillColour()
05500 {
05501     return m_bUseLocalFillColour;
05502 }
05503 
05504 
05505 /********************************************************************************************
05506 
05507 >   void PathProcessorBrush::SetUseLocalFillColour(BOOL UseLocal) 
05508 
05509     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05510     Created:    6/10/99
05511     Inputs:     the flag saying whether or not to use our local fill
05512     Returns:    
05513     Purpose:    if this flag is set to TRUE, then the cached fill will not be used when rendering.
05514                 Instead the nearest stroke colour will be rendered.  This is so that people can 
05515                 drop colours onto the brush.
05516     SeeAlso:    -
05517 
05518 ********************************************************************************************/
05519 
05520 void PathProcessorBrush::SetUseLocalFillColour(BOOL UseLocal)
05521 {
05522     m_bUseLocalFillColour = UseLocal;
05523     
05524     // we want to switch our named colours option off, the semantics of this seem a little
05525     // wrong because we are not going to use named colours, perhaps I need a new name
05526     if (UseLocal)
05527         m_bUseNamedColours = TRUE;
05528 }
05529 
05530 
05531 /********************************************************************************************
05532 
05533 >   INT32 PathProcessorBrush::GetBrushTransparency()
05534 
05535     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05536     Created:    6/10/99
05537     Inputs:     -
05538     Returns:    our transparency value (-1 indicates unused)
05539     Purpose:    as above
05540     SeeAlso:    -
05541 
05542 ********************************************************************************************/
05543 
05544 INT32 PathProcessorBrush::GetBrushTransparency()
05545 {
05546     return m_BrushTransparency;
05547 }
05548 
05549 
05550 /********************************************************************************************
05551 
05552 >   BOOL PathProcessorBrush::SetBrushTransparency(INT32 Value)
05553 
05554     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05555     Created:    6/10/99
05556     Inputs:     Value - the value to set
05557     Returns:    our transparency value (-1 indicates unused)
05558     Purpose:    as above
05559     SeeAlso:    -
05560 
05561 ********************************************************************************************/
05562 
05563 BOOL PathProcessorBrush::SetBrushTransparency(INT32 Value)
05564 {
05565     if (Value > MAX_TRANSP_VALUE)
05566         return FALSE;
05567 
05568     m_BrushTransparency = Value;
05569     return TRUE;
05570 }
05571 
05572 
05573 /********************************************************************************************
05574 
05575 >   BOOL PathProcessorBrush::SetTransparencyPressure(UINT32 Value)
05576 
05577     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05578     Created:    6/10/99
05579     Inputs:     Value - the value to set
05580     Returns:    
05581     Purpose:    Sets the extent to which pressure affects transparency
05582     SeeAlso:    -
05583 
05584 ********************************************************************************************/
05585 
05586 BOOL PathProcessorBrush::SetTransparencyPressure(UINT32 Value)
05587 {
05588     m_TranspMaxPressure = Value;
05589     return TRUE;
05590 }
05591 
05592 
05593 /********************************************************************************************
05594 
05595 >   BOOL PathProcessorBrush::SetTransparencyPressure(UINT32 Value)
05596 
05597     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05598     Created:    6/10/99
05599     Inputs:     Value - the value to set
05600     Returns:    
05601     Purpose:    Sets the extent to which pressure affects transparency
05602     SeeAlso:    -
05603 
05604 ********************************************************************************************/
05605 
05606 UINT32 PathProcessorBrush::GetTransparencyPressure()
05607 {
05608     return m_TranspMaxPressure;
05609 }
05610 
05611 /********************************************************************************************
05612 
05613 >   BOOL PathProcessorBrush::GetUseLocalFillTransp() 
05614 
05615     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05616     Created:    6/10/99
05617     Inputs:     -
05618     Returns:    the flag saying whether or not to use our local transparency
05619     Purpose:    as above
05620     SeeAlso:    -
05621 
05622 ********************************************************************************************/
05623 
05624 BOOL PathProcessorBrush::GetUseLocalTransp()
05625 {
05626     return m_bUseLocalTransp;
05627 }
05628 
05629 
05630 /********************************************************************************************
05631 
05632 >   void PathProcessorBrush::SetUseLocalTransp(BOOL UseLocal) 
05633 
05634     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05635     Created:    6/10/99
05636     Inputs:     the flag saying whether or not to use our local transparency
05637     Returns:    
05638     Purpose:    if this flag is set to TRUE then any cached transparencies will not be rendered.
05639                 Instead the transparency applied to our parent ink object will be rendered.
05640     SeeAlso:    -
05641 
05642 ********************************************************************************************/
05643 
05644 void PathProcessorBrush::SetUseLocalTransp(BOOL UseLocal)
05645 {
05646     m_bUseLocalTransp = UseLocal;
05647 }
05648 
05649 
05650 /********************************************************************************************
05651 
05652 >   BOOL PathProcessorBrush::GetUseNamedColours() 
05653 
05654     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05655     Created:    6/10/99
05656     Inputs:     -
05657     Returns:    the flag saying whether or not to use our named colours when rendering
05658     Purpose:    as above
05659     SeeAlso:    -
05660 
05661 ********************************************************************************************/
05662 
05663 BOOL PathProcessorBrush::GetUseNamedColours()
05664 {
05665     return m_bUseNamedColours;
05666 }
05667 
05668 
05669 /********************************************************************************************
05670 
05671 >   void PathProcessorBrush::SetUseNamedColours(BOOL Value
05672 
05673     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05674     Created:    6/10/99
05675     Inputs:     the flag saying whether or not to use our named colours
05676     Returns:    
05677     Purpose:    if this flag is set to FALSE then any named colours in our brush will not be 
05678                 rendered, instead we will use the local stroke colour
05679     SeeAlso:    -
05680 
05681 ********************************************************************************************/
05682 
05683 void PathProcessorBrush::SetUseNamedColours(BOOL Value)
05684 {
05685     m_bUseNamedColours = Value;
05686     if (!Value)
05687         m_bUseLocalFillColour = FALSE;
05688 }
05689 
05690 
05691 /********************************************************************************************
05692 
05693 >   void PathProcessorBrush::CopyBrushData(BrushData* pData) 
05694 
05695     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05696     Created:    6/10/99
05697     Inputs:     -
05698     Returns:    pData - pointer to the brushdata object
05699     Purpose:    copies the info from the path processor to the brushdata object
05700     SeeAlso:    -
05701 
05702 ********************************************************************************************/
05703 
05704 void PathProcessorBrush::CopyBrushData(BrushData* pData)
05705 {
05706     if (pData == NULL)
05707     {
05708         ERROR3("NULL brush data object");
05709         return;
05710     }
05711 
05712     pData->m_BrushHandle = m_BrushHandle;
05713     
05714     pData->m_BrushScaling = m_BrushScaling;
05715     pData->m_BrushScalingIncr = m_BrushScalingIncr;
05716     pData->m_BrushScalingIncrConst = m_BrushScalingIncrConst;
05717     pData->m_BrushScalingMaxRand = m_BrushScalingMaxRand;
05718     pData->m_BrushScalingRandSeed = m_BrushScalingRandSeed;
05719     pData->m_ScalingMaxPressure  = m_ScalingMaxPressure;
05720 
05721     pData->m_bRotate = m_bRotate;
05722     pData->m_RotateAngle = m_RotateAngle;
05723     pData->m_RotAngleIncrConst = m_RotAngleIncrConst;
05724     pData->m_RotAngleIncrProp  = m_RotAngleIncrProp;
05725     pData->m_RotationMaxRand = m_RotationMaxRand;
05726     pData->m_RotationRandSeed = m_RotationRandSeed;
05727     pData->m_RotationMaxPressure = m_RotationMaxPressure;
05728 
05729     pData->m_BrushSpacing  = m_BrushSpacing;
05730     pData->m_BrushSpacingIncrConst = m_BrushSpacingIncrConst;
05731     pData->m_BrushSpacingIncrProp = m_BrushSpacingIncrProp;
05732     pData->m_BrushSpacingMaxRand = m_BrushSpacingMaxRand;
05733     pData->m_BrushSpacingRandSeed = m_BrushSpacingRandSeed;
05734 
05735     pData->m_PathOffsetType = m_PathOffsetType;
05736     pData->m_PathOffsetValue = m_PathOffsetValue;
05737     pData->m_PathOffsetIncrConst = m_PathOffsetIncrConst;
05738     pData->m_PathOffsetIncrProp = m_PathOffsetIncrProp;
05739     pData->m_OffsetValueMaxRand = m_OffsetValueMaxRand;
05740     pData->m_OffsetValueRandSeed = m_OffsetValueRandSeed;
05741     pData->m_OffsetTypeRandSeed = m_OffsetTypeRandSeed;
05742 
05743     pData->m_bTile = m_bTile;
05744 
05745     pData->m_SequenceType = m_SequenceType;
05746     pData->m_SequenceRandSeed = m_SequenceRandSeed;
05747 
05748     pData->m_bUseLocalFillColour = m_bUseLocalFillColour;
05749     pData->m_bUseLocalTransp = m_bUseLocalTransp;
05750     pData->m_bUseNamedColour = m_bUseNamedColours;
05751     
05752     if (m_pParentAttr != NULL)
05753         pData->m_bTimeStampBrushes = m_pParentAttr->IsTimeStamping();
05754     else
05755         pData->m_bTimeStampBrushes = FALSE;
05756 
05757     pData->m_TimeStampPeriod = (UINT32)-1;
05758 
05759         
05760     pData->m_BrushHueIncrement = m_BrushHueIncrement;
05761     pData->m_BrushHueMaxRand = m_BrushHueMaxRand;
05762     pData->m_BrushHueRandSeed = m_BrushHueRandSeed;
05763     pData->m_BrushSatIncrement = m_BrushSatIncrement;
05764     pData->m_BrushSatMaxRand = m_BrushSatMaxRand;
05765     pData->m_BrushSatRandSeed = m_BrushSatRandSeed; 
05766 
05767     pData->m_BrushTransparency = m_BrushTransparency;
05768     pData->m_TranspMaxPressure = m_TranspMaxPressure;
05769 
05770     // Get the name from the definition
05771     BrushDefinition* pDef = GetOurBrushDefinition();
05772 
05773     if (pDef)
05774         pData->m_Name = *pDef->GetLineName();
05775 }
05776 
05777 
05778 /********************************************************************************************
05779 
05780 >   void PathProcessorBrush::CopyDataFromObject(BrushData* pData) 
05781 
05782     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05783     Created:    6/10/99
05784     Inputs:     -
05785     Returns:    pData - pointer to the brushdata object
05786     Purpose:    copies the info from the brushdata object to the processor
05787     SeeAlso:    -
05788 
05789 ********************************************************************************************/
05790 
05791 void PathProcessorBrush::CopyDataFromObject(BrushData* pData)
05792 {
05793     if (pData == NULL)
05794     {
05795         ERROR3("NULL brush data object");
05796         return;
05797     }   
05798     m_BrushHandle = pData->m_BrushHandle;
05799 
05800     // scaling
05801     SetBrushScaling(pData->m_BrushScaling);
05802     m_BrushScalingIncr = pData->m_BrushScalingIncr;
05803     m_BrushScalingIncrConst = pData->m_BrushScalingIncrConst;
05804     m_BrushScalingMaxRand = pData->m_BrushScalingMaxRand;
05805     m_BrushScalingRandSeed = pData->m_BrushScalingRandSeed;
05806     m_ScalingMaxPressure   = pData->m_ScalingMaxPressure;
05807 
05808     // rotation
05809     m_bRotate = pData->m_bRotate;
05810     SetRotationAngle(pData->m_RotateAngle);
05811     m_RotAngleIncrConst = pData->m_RotAngleIncrConst;
05812     m_RotAngleIncrProp  = pData->m_RotAngleIncrProp;
05813     m_RotationMaxRand = pData->m_RotationMaxRand;
05814     m_RotationRandSeed = pData->m_RotationRandSeed;
05815 
05816     //spacing
05817     SetSpacing(pData->m_BrushSpacing);
05818     m_BrushSpacingIncrConst = pData->m_BrushSpacingIncrConst;
05819     m_BrushSpacingIncrProp = pData->m_BrushSpacingIncrProp;
05820     m_BrushSpacingMaxRand = pData->m_BrushSpacingMaxRand;
05821     m_BrushSpacingRandSeed = pData->m_BrushSpacingRandSeed;
05822 
05823     //offset
05824     m_PathOffsetType = pData->m_PathOffsetType;
05825     SetPathOffsetValue(pData->m_PathOffsetValue);
05826     m_PathOffsetIncrConst = pData->m_PathOffsetIncrConst;
05827     m_PathOffsetIncrProp = pData->m_PathOffsetIncrProp;
05828     m_OffsetValueMaxRand = pData->m_OffsetValueMaxRand;
05829     m_OffsetValueRandSeed = pData->m_OffsetValueRandSeed;
05830     m_OffsetTypeRandSeed = pData->m_OffsetTypeRandSeed;
05831 
05832     // colour variation
05833     m_BrushHueMaxRand    = pData->m_BrushHueMaxRand;
05834     m_BrushHueRandSeed   = pData->m_BrushHueRandSeed;
05835     m_BrushSatMaxRand    = pData->m_BrushSatMaxRand;
05836     m_BrushSatRandSeed   = pData->m_BrushSatRandSeed;
05837 
05838     // Transparency
05839     m_BrushTransparency  = pData->m_BrushTransparency;
05840     m_TranspMaxPressure  = pData->m_TranspMaxPressure;
05841 
05842 
05843     m_bTile = pData->m_bTile;
05844 
05845     m_SequenceType = pData->m_SequenceType;
05846     m_SequenceRandSeed = pData->m_SequenceRandSeed;
05847 
05848     m_bUseLocalFillColour = pData->m_bUseLocalFillColour;
05849     m_bUseLocalTransp = pData->m_bUseLocalTransp;
05850     m_bUseNamedColours = pData->m_bUseNamedColour;
05851     
05852 
05853 }
05854 
05855 
05856 /********************************************************************************************
05857 
05858 >   void PathProcessorBrush::SetParentAttribute(AttrBrushType* pAttrVal) 
05859 
05860     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05861     Created:    6/10/99
05862     Inputs:     the attribute for this ppb
05863     Returns:    -
05864     Purpose:    as above
05865     SeeAlso:    -
05866 
05867 ********************************************************************************************/
05868 
05869 void PathProcessorBrush::SetParentAttribute(AttrBrushType* pAttr)
05870 {
05871     m_pParentAttr = pAttr;
05872 }
05873 
05874 
05875 /********************************************************************************************
05876 
05877 >   void PathProcessorBrush::GetParentAttribute() 
05878 
05879     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05880     Created:    6/10/99
05881     Inputs:     -
05882     Returns:    -
05883     Purpose:    returns the attribute associated with this ppb
05884     SeeAlso:    -
05885 
05886 ********************************************************************************************/
05887 
05888 AttrBrushType* PathProcessorBrush::GetParentAttribute()
05889 {
05890     return m_pParentAttr;
05891 }
05892 
05893 
05894 
05895 /********************************************************************************************
05896 
05897 >   void PathProcessorBrush::SetMaxScaling(double Value)
05898 
05899     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05900     Created:    6/10/99
05901     Inputs:     the value to set
05902     Returns:    sets the flag saying whether or not to scale to the line width
05903     Purpose:    as above
05904     SeeAlso:    -
05905 
05906 ********************************************************************************************/
05907 
05908 void PathProcessorBrush::SetMaxScaling(double Value)
05909 {
05910     m_MaxScaling = Value;
05911 }
05912 
05913 
05914 /********************************************************************************************
05915 
05916 >   void PathProcessorBrush::SetScaleToLineWidth(BOOL Value) 
05917 
05918     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05919     Created:    6/10/99
05920     Inputs:     the value to set
05921     Returns:    sets the flag saying whether or not to scale to the line width
05922     Purpose:    as above
05923     SeeAlso:    -
05924 
05925 ********************************************************************************************/
05926 
05927 void PathProcessorBrush::SetScaleToLineWidth(BOOL Value)
05928 {   
05929     m_bScaleToLineWidth = Value;
05930 }
05931 
05932 
05933 
05934 /********************************************************************************************
05935 
05936 >   void PathProcessorBrush::ScaleToValue(MILLIPOINT Value, BOOL IgnorePressure = FALSE) 
05937 
05938     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05939     Created:    6/10/99
05940     Inputs:     the value to scale to
05941     Returns:    -
05942     Purpose:    Scales the brush object such that the height of the largest object is equal to Value.
05943                 Note that as of 27/10/2000 this must incorporate offset, scaling and rotation values.   
05944     SeeAlso:    -
05945 
05946 ********************************************************************************************/
05947 
05948 void PathProcessorBrush::ScaleToValue(MILLIPOINT ScaleValue, BOOL IgnorePressure)
05949 {
05950 //  if (/*(m_bScaleToLineWidth == FALSE) ||*/ (m_LineWidth == ScaleValue))
05951 //      return;
05952 
05953 /*  if (!IgnorePressure)
05954         INT32 i = 1; // what's all this about then? AMB
05955 */
05956     MILLIPOINT Height = GetBrushSize(IgnorePressure);
05957     double ScaleFactor = double((double)ScaleValue / (double)Height);
05958 
05959     
05960     //TRACEUSER( "Diccon", _T("Scaling to value %f\n"), ScaleFactor);
05961     if (ScaleFactor <= 0.0)
05962     {
05963         //ERROR3("Argh - attempting to scale below zero");
05964         ScaleFactor = 1.0;
05965     }
05966 
05967     SetBrushScaling(ScaleFactor);
05968     m_LineWidth = ScaleValue;
05969 }
05970 
05971 
05972 
05973 /********************************************************************************************
05974 
05975 >   double PathProcessorBrush::ScaleToValue(MILLIPOINT Value) 
05976 
05977     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05978     Created:    6/10/99
05979     Inputs:     the value to scale to
05980     Returns:    the scaling value required to scale to the value given, or -1 if something went wrong
05981     Purpose:    as above, but simply retuns the value
05982     SeeAlso:    -
05983 
05984 ********************************************************************************************/
05985 
05986 double PathProcessorBrush::GetScaleValue(MILLIPOINT Value)
05987 {
05988     MILLIPOINT Height = GetBrushSize();
05989     double ScaleFactor = double((double)Value / (double)Height);
05990 
05991     return ScaleFactor;
05992 }
05993 
05994 /********************************************************************************************
05995 
05996 >   MILLIPOINT PathProcessorBrush::GetBrushSize()
05997 
05998     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
05999     Created:    6/10/99
06000     Inputs:     -
06001     Returns:    the height of the largest bounding box, to be used as a default line width
06002     Purpose:    as above
06003     SeeAlso:    -
06004 
06005 ********************************************************************************************/
06006 
06007 MILLIPOINT PathProcessorBrush::GetBrushSize(BOOL IgnorePressure)
06008 {
06009     BrushDefinition* pBrushDef = GetOurBrushDefinition();
06010     if (pBrushDef == NULL)
06011         return -1;
06012     DocRect BRect = pBrushDef->GetLargestBoundingBox();
06013     if (BRect.IsEmpty())
06014         return -1;
06015 
06016     MILLIPOINT Height = BRect.Height();
06017     MILLIPOINT Width = BRect.Width();
06018 //  double dHeight = (double)Height;
06019 //  double dWidth = (double)Width;
06020 
06021     double ScaleFactor = 1.0;
06022 
06023     // firstly, if we are rotated, or have random rotation, then use the longest side
06024     if (m_RotationMaxRand > 0 || m_RotateAngle != 0.0 || !m_bRotate)
06025     {
06026         if (Width > Height)
06027             Height = Width;
06028     }
06029     
06030     if (m_BrushScalingMaxRand > 0)
06031     {
06032         // find out the random range
06033         UINT32 Lower = 0;
06034         UINT32 Upper = 0;
06035         GetRandomLimits(100, m_BrushScalingMaxRand, &Lower, &Upper);
06036         
06037         //Use the upper limit
06038         ScaleFactor *= ((double)Upper * 0.01);
06039     }
06040 
06041 /*  if (m_ScalingMaxPressure > 0 && !IgnorePressure)
06042     {
06043         ScaleFactor *= ((double)m_ScalingMaxPressure * 0.01 + 1.0);
06044         
06045     }
06046 */
06047     MILLIPOINT NewHeight = (MILLIPOINT)((double)Height * ScaleFactor);
06048 
06049     // if we have random offset then there will be some effect, this is separate from the offset amount
06050     if (m_OffsetValueMaxRand > 0)
06051     {
06052         // rand value is a percentage of object size
06053         double RandMultiplier = (double)m_OffsetValueMaxRand * 0.01;
06054         double OffsetAmount = (double)Height * RandMultiplier;
06055         
06056         // remember that it goes both sides
06057         MILLIPOINT mpAmount = (MILLIPOINT)(2*OffsetAmount);
06058         NewHeight += mpAmount;
06059     }
06060 
06061     switch (m_PathOffsetType)
06062     {
06063         case OFFSET_NONE:
06064             break;
06065         case OFFSET_LEFT:
06066         case OFFSET_RIGHT:
06067         case OFFSET_ALTERNATE:
06068         {
06069             MILLIPOINT OffsetIncr = 2 * m_PathOffsetValue;
06070             NewHeight += OffsetIncr;
06071         }
06072         break;
06073         case OFFSET_RANDOM:
06074             break;
06075         default:
06076             ERROR3("Invalid offset type");
06077     }
06078 
06079     return NewHeight;
06080 }
06081 
06082 
06083 
06084 
06085 /********************************************************************************************
06086 
06087 >   double PathProcessorBrush::GetAngleAtDistance(MILLIPOINT Distance) 
06088 
06089     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06090     Created:    6/10/99
06091     Inputs:     
06092     Returns:    The rotation angle to be applied to the brush object at this point
06093     Purpose:    Pretty much as above, but with the following notes:
06094                 There are several different ways of applying a rotation angle to brush objects:
06095                 
06096                 - Rotate along the path(i.e. rotate according to the tangent of the path at this point)
06097                 this is not included here, as the path tangent is known by the time you get to RenderBrushAtPoint
06098                 
06099                 - Constant angle of rotation, as set by the m_RotateAngle member
06100                 
06101                 - Random a random fn. determines a different value for each distance
06102 
06103     SeeAlso:    -
06104 
06105 ********************************************************************************************/
06106 
06107 double PathProcessorBrush::GetNextAngle()
06108 {
06109     double NewAngle = m_LastRotationNoRandom;
06110     
06111     NewAngle += m_RotAngleIncrConst;
06112     m_LastRotationNoRandom = NewAngle;
06113     double Rand = 0;
06114     double PressureAngle = 1.0;
06115 #ifdef USE_MTRNG
06116     if (m_RotationMaxRand != 0)
06117     {
06118         if (m_pRotationRNG != NULL)
06119         {
06120             // first find out our random range
06121 //          UINT32 UpperLimit = 0;
06122 //          UINT32 LowerLimit = 0;
06123 
06124         //  GetRotationRandomLimits(100, m_RotationMaxRand, &LowerLimit, &UpperLimit);
06125 
06126             Rand = (double)m_pRotationRNG->GetNextRandomNumberScaled(m_RotationMaxRand, 0);
06127 
06128 //double R =  (Rand * 0.01) * 360;
06129 //TRACEUSER( "Phil", _T("Random = %f, Random angle = %f\n"), Rand, R);
06130         }
06131         else
06132             ERROR3("Rotation RNG is NULL");
06133     }
06134     
06135 #endif
06136     if (m_RotationMaxPressure > 0 && m_bValidPressure)
06137     {
06138         UINT32 PressureVal = GetCurrentPressureEffect(m_RotationMaxPressure);
06139         //TRACEUSER( "Diccon", _T("Pressure adj = %d\n"), PressureVal);
06140         PressureAngle = (double)PressureVal / 100; //* 180;
06141     
06142     }
06143     m_LastAngle = (NewAngle * PressureAngle) + Rand;
06144 
06145     while (m_LastAngle > 360)
06146         m_LastAngle -= 360;
06147     //TRACEUSER( "Diccon", _T("Next angle = %f\n"), m_LastAngle);
06148     return m_LastAngle;
06149 }
06150 
06151 /********************************************************************************************
06152 
06153 >   double PathProcessorBrush::GetNextScaling() 
06154 
06155     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06156     Created:    6/10/99
06157     Inputs:     
06158     Returns:    The scaling to be applied to the brush object at this point
06159     Purpose:    Pretty much as above, but with the following notes:
06160                 There are several different ways of applying a rotation angle to brush objects:
06161                 
06162                 - Constant scaling, as set by the m_BrushScaling member
06163                 - Increasing/decreasing as set by m_ScalingIncr and m_LastScaling
06164                 - Random - a random fn. provides a value to be applied
06165 
06166     SeeAlso:    -
06167 
06168 ********************************************************************************************/
06169 
06170 double PathProcessorBrush::GetNextScaling(UINT32 Index)
06171 {
06172     ERROR2IF(m_LastScaling < 0, 1.0, "Invalid scaling value");
06173     ERROR2IF(m_BrushScalingIncr <= 0, 1.0, "Invalid scaling value");
06174     
06175     double NewScaling = m_BrushScaling;
06176     if (Index > 0)
06177         NewScaling = m_LastScalingNoRandom; 
06178     double RandomScale = 1.0;
06179     double PressureScale = 1.0;
06180 
06181     // record the last value before randomness
06182     m_LastScalingNoRandom = NewScaling;
06183     if (m_BrushScalingMaxRand != 0)
06184     {
06185 #ifdef USE_MTRNG
06186         if (m_pScalingRNG != NULL)
06187         {
06188             // first find out our random range
06189             UINT32 UpperLimit = 0;
06190             UINT32 LowerLimit = 0;
06191 
06192             GetRandomLimits(100, m_BrushScalingMaxRand, &LowerLimit, &UpperLimit);
06193             // we want our random numbers in the range 100% +/- MaxRand
06194             UINT32 Random = m_pScalingRNG->GetNextRandomNumberScaled(UpperLimit, LowerLimit, 100);
06195                                                                    
06196             //TRACEUSER( "Diccon", _T("Random val =  %d\n"), Random);
06197             RandomScale = (double)Random / 100; 
06198 //TRACEUSER( "Phil", _T("Scaling = %f\n"), m_BrushScaling * RandomScale);
06199         }
06200 #endif  
06201     }
06202     if (m_ScalingMaxPressure > 0 && m_bValidPressure)
06203     {
06204         UINT32 PressureVal = GetCurrentPressureEffect(m_ScalingMaxPressure, TRUE);
06205         
06206         PressureScale = (double)PressureVal / 100;
06207     //  TRACEUSER( "Diccon", _T("Pressure Val = %d, Scale = %f\n"), PressureVal, PressureScale);
06208     }
06209     
06210     NewScaling = NewScaling * RandomScale * PressureScale;
06211 
06212     // we're no longer stopping you from going under the minimum scaling, but there is code in place
06213     // to break out of the rendering loop if you do so.
06214 
06215 /*  if (NewScaling <= MIN_BRUSH_SCALE)
06216         NewScaling = MIN_BRUSH_SCALE;
06217     else */
06218     {
06219         if (NewScaling >= m_MaxScaling)
06220                 NewScaling = m_MaxScaling;
06221     }
06222 
06223     // if its the first object then we want to return the actual scaling value, 
06224     // not the change in scaling
06225     double NextScaling = NewScaling;
06226     
06227     if (!m_UseActualScaling)
06228         NextScaling = NewScaling / m_LastScalingRendered;
06229     
06230     m_LastScaling = NewScaling;
06231     
06232     //TRACEUSER( "Diccon", _T("Actual Scaling = %f, Next Scaling = %f, Last Rendered = %f\n"), NewScaling, NextScaling, m_LastScalingRendered);
06233 
06234     return NextScaling;
06235 }
06236 
06237 
06238 /********************************************************************************************
06239 
06240 >   MILLIPOINT PathProcessorBrush::GetNextSpacing() 
06241 
06242     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06243     Created:    6/10/99
06244     Inputs:     -
06245     Returns     the next spacing to use
06246     Purpose:    Returns the next spacing to use, this can be determined in several ways, as
06247                 with the other object placement attributes.
06248 
06249     SeeAlso:    -
06250 
06251 ********************************************************************************************/
06252 
06253 MILLIPOINT PathProcessorBrush::GetNextSpacing()
06254 {
06255     ERROR2IF(m_LastSpacing <= 0, 10000, "Invalid last spacing");
06256     ERROR2IF(m_BrushSpacing <= 0, 10000, "Invalid spacing value");
06257     
06258     // start of with the previous spacing value, before it had its random effect added.
06259     // If we don't do this then we end up with a random walk effect, always getting either
06260     // bigger or smaller
06261     MILLIPOINT NewSpacing = m_LastSpacingNoRandom;
06262     
06263     // do the proportional incrementfirst
06264     if (m_BrushSpacingIncrProp != 1.0)
06265         NewSpacing = (MILLIPOINT)(m_BrushSpacingIncrProp * m_LastSpacing);
06266     
06267     // add the constant increment
06268     if (m_BrushSpacingIncrConst != 0)
06269         NewSpacing += m_BrushSpacingIncrConst;
06270     
06271     // store this value so we can use it next time
06272     m_LastSpacingNoRandom = NewSpacing;
06273 
06274     if (m_BrushSpacingMaxRand != 0)
06275     {
06276 #ifdef USE_MTRNG
06277         if (m_pSpacingRNG != NULL)
06278         {
06279             // first find out our random range
06280             UINT32 UpperLimit = 0;
06281             UINT32 LowerLimit = 0;
06282 
06283             GetRandomLimits(100, m_BrushSpacingMaxRand, &LowerLimit, &UpperLimit);
06284             // we want our random numbers in the range 100% +/- MaxRand
06285             //UINT32 Random = m_pSpacingRNG->GetNextRandomNumberScaled(100 + m_BrushSpacingMaxRand,
06286             //                                                      100 - m_BrushSpacingMaxRand);
06287             
06288             // now ask our RNG to get a number between these limits
06289             UINT32 Random = m_pSpacingRNG->GetNextRandomNumberScaled(UpperLimit, LowerLimit/2, 100);
06290         
06291             // we treat our numbers as percentages
06292             double Mult = (double)Random / 100;
06293             //TRACEUSER( "Diccon", _T("Random spacing multiplier = %f\n"), Mult);
06294             NewSpacing = (MILLIPOINT)(((double)NewSpacing) * Mult);
06295     
06296         }
06297 #endif
06298     }
06299     if (m_SpacingMaxPressure > 0 && m_bValidPressure)
06300     {
06301         UINT32 PressureVal = GetCurrentPressureEffect(m_SpacingMaxPressure);
06302     //  TRACEUSER( "Diccon", _T("Pressure adj = %d\n"), PressureVal);
06303         double PressureScale = (double)PressureVal / 100;
06304         NewSpacing = (MILLIPOINT)((double)NewSpacing * PressureScale);
06305     }
06306     
06307     
06308 
06309     if (NewSpacing < MIN_BRUSH_SPACING)
06310         NewSpacing = MIN_BRUSH_SPACING;
06311     else 
06312     {
06313         if (NewSpacing > MAX_BRUSH_SPACING)
06314             NewSpacing = MAX_BRUSH_SPACING;
06315     }
06316 
06317     m_LastSpacing = NewSpacing;
06319     return m_LastSpacing;
06320 }
06321 
06322 
06323 /********************************************************************************************
06324 
06325 >   UINT32 PathProcessorBrush::GetNextInkObject(UINT32 LastObject, UINT32 NumObjects) 
06326 
06327     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06328     Created:    6/10/99
06329     Inputs:     Lastobject - the index of the last object rendered
06330                 Numobjects - the number of ink objects in this brush
06331     Returns     the index number of the next ink object to use
06332     Purpose:    as above
06333 
06334     SeeAlso:    -
06335 
06336 ********************************************************************************************/
06337 
06338 UINT32 PathProcessorBrush::GetNextInkObject(UINT32 LastObject, UINT32 NumObjects)
06339 {
06340     if (LastObject > NumObjects)
06341     {
06342         ERROR3("Duh, last object can't be greater than maximum");
06343         return 0;
06344     }
06345     UINT32 RetVal = 0;
06346     switch (m_SequenceType)
06347     {
06348         case SEQ_FORWARD:
06349             if (LastObject < NumObjects -1)
06350                 RetVal=  ++LastObject;
06351             else
06352                 RetVal =  0;
06353             break;
06354         case SEQ_BACKWARD:
06355             if (LastObject > 0)
06356                 RetVal = --LastObject;
06357             else
06358                 RetVal =  NumObjects -1;
06359             break;
06360         case SEQ_MIRROR:
06361             // go forward if we are ascending
06362             if (m_MirrorSeqAscend)
06363             {
06364                 if (LastObject < NumObjects -1)
06365                         RetVal = ++LastObject;
06366                 else
06367                 {
06368                     m_MirrorSeqAscend = FALSE;
06369                     RetVal = NumObjects -1;
06370                 }
06371             }
06372             else // go backward if we are descending
06373             {
06374                 if (LastObject > 0)
06375                     RetVal =  --LastObject;
06376                 else
06377                 {
06378                     m_MirrorSeqAscend = TRUE;
06379                     RetVal =  0;
06380                 }
06381             }
06382             break;
06383         case SEQ_RANDOM:
06384             //RetVal =  GetNextRandomNumberScaled(NumObjects, 0);
06385             if (m_pSequenceRNG != NULL)
06386             {
06387                 RetVal = m_pSequenceRNG->GetNextRandomNumberScaled(NumObjects, 0);
06388             }
06389             else
06390             {
06391                 ERROR3("Trying to get a random number with no RNG");
06392             }
06393 
06394             break;
06395         default:
06396             ERROR3("invalid sequence type");
06397             RetVal = 0;
06398             break;
06399     }
06400     // quick check
06401     if (RetVal >= NumObjects)
06402         RetVal--;
06403 
06404 //  TRACEUSER( "Diccon", _T("Ink object = %d, "), RetVal);
06405     return RetVal;
06406 
06407 
06408 }
06409 
06410 
06411 
06412 /********************************************************************************************
06413 
06414 >   MILLIPOINT PathProcessorBrush::GetNextOffset() 
06415 
06416     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06417     Created:    6/10/99
06418     Inputs:     -
06419     Returns     the next offset to use
06420     Purpose:    as above
06421 
06422     SeeAlso:    -
06423 
06424 ********************************************************************************************/
06425 
06426 MILLIPOINT PathProcessorBrush::GetNextOffset()
06427 {
06428     ERROR2IF(m_LastOffset < 0, 0, "Invalid last Offset");
06429     ERROR2IF(m_PathOffsetValue < 0, 0, "Invalid Offset value");
06430     
06431     MILLIPOINT NewOffset = m_LastOffsetNoRandom;
06432 
06433     // do the proportional incrementfirst
06434     if (m_PathOffsetIncrProp != 1.0)
06435         NewOffset = (MILLIPOINT)(m_PathOffsetIncrProp * m_LastOffset);
06436     
06437     // add the constant increment
06438     if (m_PathOffsetIncrConst != 0)
06439         NewOffset += m_PathOffsetIncrConst;
06440     
06441     m_LastOffsetNoRandom = NewOffset;
06442     
06443 #ifdef USE_MTRNG
06444     if (m_OffsetValueMaxRand > 0)
06445     {
06446     //  if (m_PathOffsetValue > 0)
06447         {
06448             if (m_pOffsetValueRNG != NULL)
06449             {
06450                 // first find out our random range
06451 //              UINT32 UpperLimit = 0;
06452                 UINT32 LowerLimit = 0;
06453 
06454             //  GetRandomLimits(100, m_OffsetValueMaxRand, &LowerLimit, &UpperLimit);
06455 
06456                 // we want our random numbers in the range 100% +/- MaxRand
06457                 UINT32 Random = m_pOffsetValueRNG->GetNextRandomNumberScaled(m_OffsetValueMaxRand, LowerLimit);
06458                 
06459                 double Mult = (double)Random / 100;
06460 
06461                 BrushDefinition* pBrushDef = GetOurBrushDefinition();
06462                 if (pBrushDef != NULL)
06463                 {
06464                     DocRect BRect = pBrushDef->GetLargestBoundingBox();
06465                     if (!BRect.IsEmpty())
06466                     {
06467                         double Height = (double)BRect.Height();
06468                         Height = Height * Mult;     
06469 
06470                         NewOffset += (INT32)Height;
06471                     }
06472                 }
06473 
06474                 //NewOffset = (MILLIPOINT)(((double)NewOffset) * Mult);
06475                 //TRACEUSER( "Diccon", _T("Spacing = %d\n"), NewSpacing);
06476             }
06477             else
06478                 ERROR3("OffsetVal RNG  is NULL");
06479         }
06480     }
06481 #endif
06482     
06483 
06484     if (NewOffset < 0)
06485         NewOffset = 0;
06486     else 
06487     {
06488         if (NewOffset > MAX_BRUSH_OFFSET)
06489             NewOffset = MAX_BRUSH_OFFSET;
06490     }
06491     m_LastOffset = NewOffset;
06492 //  TRACEUSER( "Diccon", _T("Offset = %d\n"), m_LastOffset);
06493     return m_LastOffset;
06494 }
06495 
06496 
06497 
06498 /********************************************************************************************
06499 
06500 >   double PathProcessorBrush::GetNextSaturationMultiplier()
06501 
06502     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06503     Created:    6/10/99
06504     Inputs:     -
06505     Returns     the next saturation multiplier
06506     Purpose:    this differs slightly from the other GetNext functions in that it does not return
06507                 a saturation value. Instead it returns a multiplier value which should be given
06508                 to an HSVChanger object, the HSVChanger should then apply that multiplier to the
06509                 colours in the brush
06510 
06511     SeeAlso:    -
06512 
06513 ********************************************************************************************/
06514 
06515 double PathProcessorBrush::GetNextSaturationMultiplier()
06516 {
06517     double NextSat = 0;
06518 #ifdef USE_MTRNG
06519     if (m_BrushSatMaxRand > 0)
06520     {       
06521         if (m_pSaturationRNG != NULL)
06522         {
06523             // first find out our random range
06524             UINT32 UpperLimit = 0;
06525             UINT32 LowerLimit = 0;
06526 
06527             GetRandomLimits(100, m_BrushSatMaxRand, &LowerLimit, &UpperLimit);
06528 
06529             // we want our random numbers in the range 100% +/- MaxRand
06530             UINT32 Random = m_pSaturationRNG->GetNextRandomNumberScaled(UpperLimit, LowerLimit);
06531 
06532             // do a bit of cheating here as we want to allow negative numbers
06533             INT32 NewRand = Random - 100;
06534             double Mult = (double)NewRand / 100;
06535         //  TRACEUSER( "Diccon", _T("Sat Rand = %d\n"), NewRand);
06536             NextSat = Mult;
06537             
06538         }
06539         else
06540             ERROR3("SaturationVal RNG  is NULL");
06541     }
06542 #endif  
06543     m_LastSatMultiplier = NextSat;
06544     return NextSat;
06545 }
06546 
06547 
06548 
06549 /********************************************************************************************
06550 
06551 >   double PathProcessorBrush::GetNextHueMultiplier()
06552 
06553     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06554     Created:    6/10/99
06555     Inputs:     -
06556     Returns     the next hue multiplier
06557     Purpose:    this differs slightly from the other GetNext functions in that it does not return
06558                 a hue value. Instead it returns a multiplier value which should be given
06559                 to an HSVChanger object, the HSVChanger should then apply that multiplier to the
06560                 colours in the brush
06561 
06562     SeeAlso:    -
06563 
06564 ********************************************************************************************/
06565 
06566 double PathProcessorBrush::GetNextHueMultiplier()
06567 {
06568     double NextHue = 0;
06569 #ifdef USE_MTRNG
06570     if (m_BrushHueMaxRand > 0)
06571     {       
06572         if (m_pHueRNG != NULL)
06573         {
06574             // first find out our random range
06575 //          UINT32 UpperLimit = 0;
06576             UINT32 LowerLimit = 0;
06577 
06578         //  GetRandomLimits(100, m_BrushHueMaxRand, &LowerLimit, &UpperLimit);
06579 
06580             // we want our random numbers in the range 100% +/- MaxRand
06581             UINT32 Random = m_pHueRNG->GetNextRandomNumberScaled(m_BrushHueMaxRand*2, LowerLimit);
06582 
06583         //  INT32 RealRand = Random - 100;
06584             //double Mult = (double)RealRand / 100;
06585             NextHue = (double)Random - m_BrushHueMaxRand ;
06586         }
06587         else
06588             ERROR3("HueVal RNG  is NULL");
06589     }
06590 #endif
06591     m_LastHueMultiplier = NextHue;
06592 //  TRACEUSER( "Diccon", _T("Next Hue = %f\n"), NextHue);
06593     return NextHue;
06594 }
06595 
06596 /********************************************************************************************
06597 
06598 >   void PathProcessorBrush::SetNextOffsetType() 
06599 
06600     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06601     Created:    6/10/99
06602     Inputs:     -
06603     Returns     -
06604     Purpose:    Asks the processor to determine its next offset type and record it in a data member.
06605                 This only occurs if the processor has its path offset type set to random.
06606                 If you are calling RenderBrushAtPoint externally rather than from ProcessPath
06607                 then you should call this for each ink object
06608 
06609     SeeAlso:    -
06610 
06611 ********************************************************************************************/
06612 
06613 void PathProcessorBrush::SetNextOffsetType()
06614 {
06615     if (m_PathOffsetType == OFFSET_RANDOM)
06616         m_LastOffsetType = GetNextOffsetType();
06617     else
06618         m_LastOffsetType = OFFSETTYPE_CENTRE; // default to centre
06619 }
06620 
06621 
06622 /********************************************************************************************
06623 
06624 >   UINT32 PathProcessorBrush::GetNextOffsetType() 
06625 
06626     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06627     Created:    6/10/99
06628     Inputs:     -
06629     Returns     the next offset type
06630     Purpose:    as above
06631 
06632     SeeAlso:    -
06633 
06634 ********************************************************************************************/
06635 UINT32 PathProcessorBrush::GetNextOffsetType()
06636 
06637 
06638 {
06639 
06640     if (m_PathOffsetType != OFFSET_RANDOM )
06641     {
06642         //ERROR3("Trying to get random offset type when we shouldn't be");
06643         return OFFSETTYPE_CENTRE;
06644     }
06645     
06646     UINT32 Offset = OFFSETTYPE_CENTRE;
06647 #ifdef USE_MTRNG
06648     if (m_pOffsetTypeRNG == NULL)
06649     {
06650         ERROR3("Offset Type RNG is NULL");
06651         return OFFSETTYPE_CENTRE;
06652     }
06653     // get a random number, if its even we go left, if its odd we go right
06654     UINT32 Rand = m_pOffsetTypeRNG->operator ()();
06655     if (Rand % 2 == 0)
06656         Offset = OFFSETTYPE_LEFT;
06657     else
06658         Offset = OFFSETTYPE_RIGHT;
06659 
06660     //TRACEUSER( "Diccon", _T("Offset Type = %d\n"), Offset);
06661 #endif
06662     return Offset;
06663 }
06664 
06665 
06666 /********************************************************************************************
06667 
06668 >   UINT32 PathProcessorBrush::GetCurrentPressureEffect(UINT32 MaxEffect) 
06669 
06670     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06671     Created:    6/10/99
06672     Inputs:     MaxEffect - the maximum % effect that pressure can have
06673                 FixedMaximum - flag indicating that the maximum should always be 100%
06674     Returns     the % effect of the current pressure
06675     Purpose:    Simply pass in the maximum effect that you allow and this returns
06676                 the effect caused by the current pressure value
06677 
06678     SeeAlso:    -
06679 
06680 ********************************************************************************************/
06681 
06682 UINT32 PathProcessorBrush::GetCurrentPressureEffect(UINT32 MaxEffect, BOOL FixedMaximum)
06683 {
06684     if (m_CurrentPressure.m_Pressure < 0 || m_CurrentPressure.m_Pressure > MAXPRESSURE)
06685     {
06686         ERROR3("Invalid pressure here Jim");
06687         return 0;
06688     }
06689     
06690     // set the maximum, we have the option to fix this at 100% if we want
06691     UINT32 MaxPercent = 100;
06692     if (!FixedMaximum)
06693         MaxPercent += MaxEffect;
06694 
06695     UINT32 MinPercent = 100 - MaxEffect;
06696     UINT32 Range = MaxPercent - MinPercent;
06697 
06698     double PressureVal = (double)((double)Range / (double)MAXPRESSURE);
06699     UINT32 CurrentPressure = (UINT32)(PressureVal * m_CurrentPressure.m_Pressure);
06700 
06701     return MinPercent + CurrentPressure;
06702 }
06703 
06704 
06705 /********************************************************************************************
06706 
06707 >   INT32 PathProcessorBrush::GetNextTransparencyAdjust()
06708 
06709     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06710     Created:    28/6/2000
06711     Inputs:     -
06712     Returns     the first transparency adjustment value 
06713     Purpose:    
06714 
06715     SeeAlso:    GetPressureTranspAdjust()
06716 
06717     Notes:      Transparency variations now work through multipliers, as opposed to the previous
06718                 replacement system.  This value returned from this function is the main transparency
06719                 adjuster value.
06720 
06721 ********************************************************************************************/
06722 
06723 double PathProcessorBrush::GetNextTransparencyAdjust()
06724 {
06725     return (double)m_BrushTransparency * 0.01;
06726 }
06727 
06728 
06729 /********************************************************************************************
06730 
06731 >   double PathProcessorBrush::GetNextTranspAdjust()
06732 
06733     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06734     Created:    28/6/2000
06735     Inputs:     -
06736     Returns     the transparency adjuster value
06737     Purpose:    as above, currently the only thing that affects transparency is pressure.  Note
06738                 that -1 indicates that we are not adjusting transparency
06739 
06740     SeeAlso:    notes for GetNextTransparency
06741 
06742 ********************************************************************************************/
06743 
06744 double PathProcessorBrush::GetNextPressureTranspAdjust()
06745 {
06746     double Retval = 1.0;
06747 
06748     if (m_TranspMaxPressure != 0)
06749     {
06750         double PressureEffect = (double)GetCurrentPressureEffect(m_TranspMaxPressure);
06751         if (PressureEffect != 100)
06752         {
06753             Retval = PressureEffect *0.01;
06754         //  TRACEUSER( "Diccon", _T("Transp adjust %f\n"), Retval);     
06755         }
06756     }
06757     return Retval;
06758 }
06759 
06760 /********************************************************************************************
06761 
06762 >   UINT32 PathProcessorBrush::GetCurrentPressure() 
06763 
06764     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06765     Created:    6/10/99
06766     Returns:    the current pressure value for the point to be rendered
06767     Purpose:    As above
06768 
06769 ********************************************************************************************/
06770 
06771 UINT32 PathProcessorBrush::GetCurrentPressure()
06772 {
06773     return m_CurrentPressure.m_Pressure;
06774 }
06775 
06776 
06777 /********************************************************************************************
06778 
06779 >   void PathProcessorBrush::SetCurrentPressure(UINT32 Pressure) 
06780 
06781     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06782     Created:    6/10/99
06783     Inputs:     the current pressure value for the point to be rendered
06784     Purpose:    As above
06785 
06786 ********************************************************************************************/
06787 
06788 void PathProcessorBrush::SetCurrentPressure(UINT32 Pressure)
06789 {
06790     if (Pressure < 0 || Pressure > MAXPRESSURE)
06791         return;
06792 
06793     m_CurrentPressure.m_Pressure = Pressure;
06794     m_bValidPressure = TRUE;
06795 }
06796 
06797 
06798 /********************************************************************************************
06799 
06800 >   void PathProcessorBrush::GetRandomLimits(UINT32 Base, UINT32 MaxRand, UINT32* pLower, UINT32* pUpper) 
06801 
06802     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06803     Created:    6/10/99
06804     Inputs:     Base - the base number which you will use to derive the limits. e.g. if you are
06805                 working in percentages then you will probably want to use 100 as your base. 
06806                 In fact this has not been tested with a base other than 100 so that is what is advised.
06807                 
06808                 MaxRand the maximum random amount, only really tested in the range 0 - 100 with 0 
06809                 being no random (i.e upperlimit = lowerlimit = base) and 100 being the maximum
06810                 (i.e. lowerlimit = base * 1/MAX_RANDOM_FACTOR and upperlimit = base * MAX_RANDOM_FACTOR
06811     Outputs:    pLower will point to a value which will be the lower bound of our random range
06812                 pUpper - similar for the upper bound
06813     Purpose:    To determine the upper and lower bounds of a random range
06814 
06815 ********************************************************************************************/
06816 
06817 
06818 void PathProcessorBrush::GetRandomLimits(UINT32 Base, UINT32 MaxRand, UINT32* pLower, UINT32* pUpper)
06819 {
06820     // quick checks
06821     if (pLower == NULL || pUpper == NULL) 
06822     {
06823         ERROR3("Illegal entry parameters in PathProcessorBrush::GetRandomLimits");
06824         return;
06825     }
06826     
06827     if (MaxRand > MAX_RANDOM_AMOUNT || MaxRand < MIN_RANDOM_AMOUNT)
06828     {
06829         ERROR3("Illegal entry parameters in PathProcessorBrush::GetRandomLimits");
06830         *pLower = Base;
06831         *pUpper = Base;
06832         return;
06833     }
06834     
06835     if (MaxRand == 0)
06836     {
06837         *pLower = Base;
06838         *pUpper = Base;
06839         return;
06840     }
06841 
06842     // so we're ok.
06843     double RandomFactor = (double)MaxRand / 100;
06844     RandomFactor = (RandomFactor * MAX_RANDOM_FACTOR) + MIN_RANDOM_FACTOR;
06845 
06846     *pLower = (UINT32)((double)Base  / RandomFactor);
06847     *pUpper  =(UINT32)((double)Base * RandomFactor);
06848 
06849     
06850     return;
06851 }
06852 
06853 
06854 /********************************************************************************************
06855 
06856 >   void PathProcessorBrush::GetRotationRandomLimits(UINT32 Base, UINT32 MaxRand, UINT32* pLower, UINT32* pUpper) 
06857 
06858     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06859     Created:    6/10/99
06860     Inputs:     Base - the base number which you will use to derive the limits. e.g. if you are
06861                 working in percentages then you will probably want to use 100 as your base. 
06862                 In fact this has not been tested with a base other than 100 so that is what is advised.
06863                 
06864                 MaxRand the maximum random amount, only really tested in the range 0 - 100 with 0 
06865                 being no random (i.e upperlimit = lowerlimit = base) and 100 being the maximum
06866                 (i.e. lowerlimit = base * 1/MAX_RANDOM_FACTOR and upperlimit = base * MAX_RANDOM_FACTOR
06867     Outputs:    pLower will point to a value which will be the lower bound of our random range
06868                 pUpper - similar for the upper bound
06869     Purpose:    To determine the upper and lower bounds of a random range, differs from the above
06870                 function in that the maximum rotation random factor is different
06871 
06872 ********************************************************************************************/
06873 
06874 void PathProcessorBrush::GetRotationRandomLimits(UINT32 Base, UINT32 MaxRand, UINT32* pLower, UINT32* pUpper) 
06875 {
06876     // quick checks
06877     if (pLower == NULL || pUpper == NULL) 
06878     {
06879         ERROR3("Illegal entry parameters in PathProcessorBrush::GetRandomLimits");
06880         return;
06881     }
06882     
06883     if (MaxRand > MAX_RANDOM_AMOUNT || MaxRand < MIN_RANDOM_AMOUNT)
06884     {
06885         ERROR3("Illegal entry parameters in PathProcessorBrush::GetRandomLimits");
06886         *pLower = Base;
06887         *pUpper = Base;
06888         return;
06889     }
06890     
06891     if (MaxRand == 0)
06892     {
06893         *pLower = Base;
06894         *pUpper = Base;
06895         return;
06896     }
06897 
06898     // so we're ok.
06899     double RandomFactor = (double)MaxRand / 100;
06900     RandomFactor = (RandomFactor * MAX_ROTATION_RANDOM_FACTOR) + MIN_RANDOM_FACTOR;
06901 
06902     *pLower = (UINT32)((double)Base  / RandomFactor);
06903     *pUpper  =(UINT32)((double)Base * RandomFactor);
06904 
06905     
06906     return;
06907 
06908 }
06909 /********************************************************************************************
06910 
06911 >   UINT32 PathProcessorBrush::GetFirstRandomNumber(UINT32 Seed = 0) 
06912 
06913     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06914     Created:    6/10/99
06915     Inputs:     a seed to use to generate the random number sequence
06916     Returns:    the first number in a random number sequence
06917     Purpose:    Seeds srand with either the seed supplied or by using time (i.e. a random seed)
06918     SeeAlso:
06919 
06920     **** SPECIAL NOTE, now that I am making use of the MT random number generators these functinos
06921     that make use of srand are only used for random sequences (i think) and maybe I should change
06922     that over too for consistency.
06923 ********************************************************************************************/
06924 /*
06925 UINT32 PathProcessorBrush::GetFirstRandomNumber(UINT32 Seed)
06926 {
06927     // seed the random number generator
06928     if (Seed == 0)
06929         srand( (unsigned)time( NULL ) );
06930     else
06931         srand((unsigned)Seed);
06932 
06933     return (UINT32)rand();
06934 }
06935 */
06936 
06937 /********************************************************************************************
06938 
06939 >   UINT32 PathProcessorBrush::GetNextRandomNumber() 
06940 
06941     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06942     Created:    6/10/99
06943     Inputs:     -
06944     Returns:    the next number in an already seeded random number sequence
06945     Purpose:    as above, note that you MUST have already seeded the sequence
06946     SeeAlso:
06947 
06948 ********************************************************************************************/
06949 /*
06950 UINT32 PathProcessorBrush::GetNextRandomNumber()
06951 {
06952     INT32 Retval =  rand();
06953     TRACEUSER( "Diccon", _T("random number = %d , "), Retval);
06954     return (UINT32)Retval;
06955 }
06956 */
06957 
06958 /********************************************************************************************
06959 
06960 >   UINT32 PathProcessorBrush::GetNextRandomNumberScaled(UINT32 MaxValue = 100, UINT32 MinValue = 0) 
06961 
06962     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06963     Created:    6/10/99
06964     Inputs:     -
06965     Returns:    the next number in an already seeded random number sequence, scaled to between
06966                 the two specified values
06967     Purpose:    as above, note that you MUST have already seeded the sequence
06968     SeeAlso:
06969 
06970 ********************************************************************************************/
06971 
06972 /*
06973 UINT32 PathProcessorBrush::GetNextRandomNumberScaled(UINT32 MaxValue, UINT32 MinValue)
06974 {
06975     UINT32 Random = GetNextRandomNumber();
06976 //  return (Random % MaxValue) + MinValue;
06977     double ScaleFactor = ((double)(MaxValue - MinValue)) / ((double)RAND_MAX);
06978     return ((UINT32)(Random * ScaleFactor) + MinValue);
06979     
06980 }
06981 */
06982 /********************************************************************************************
06983 
06984 >   void PathProcessorBrush::ResetRandomNumberGenerators() 
06985 
06986     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
06987     Created:    6/10/99
06988     Inputs:     -
06989     Returns     -
06990     Purpose:    to reset all the random number generators so that they repeat their sequence
06991                 from the beginning. Call this prior to rendering
06992     SeeAlso:    -
06993 
06994 ********************************************************************************************/
06995 
06996 BOOL PathProcessorBrush::ResetRandomNumberGenerators()
06997 {
06998 #ifdef USE_MTRNG
06999     if (m_pSpacingRNG != NULL)
07000         m_pSpacingRNG->seed((UINT32)m_BrushSpacingRandSeed);
07001     if (m_pScalingRNG !=  NULL)
07002         m_pScalingRNG->seed((UINT32)m_BrushScalingRandSeed);
07003     if (m_pOffsetTypeRNG != NULL)
07004         m_pOffsetTypeRNG->seed((UINT32)m_OffsetTypeRandSeed);
07005     if (m_pOffsetValueRNG != NULL)
07006         m_pOffsetValueRNG->seed((UINT32)m_OffsetValueRandSeed);
07007     if (m_pSaturationRNG != NULL)
07008         m_pSaturationRNG->seed((UINT32)m_BrushSatRandSeed);
07009     if (m_pHueRNG != NULL)
07010         m_pHueRNG->seed((UINT32)m_BrushHueRandSeed);
07011     if (m_pRotationRNG != NULL)
07012         m_pRotationRNG->seed((UINT32) m_RotationRandSeed);
07013     if (m_pSequenceRNG != NULL)
07014         m_pSequenceRNG->seed((UINT32) m_SequenceRandSeed);
07015 #endif
07016     return TRUE;
07017 }
07018 
07019 /********************************************************************************************
07020 
07021 >   INT32 PathProcessorBrush::HowManyObjectsInDistance(MILLIPOINT Distance) 
07022 
07023     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07024     Created:    6/10/99
07025     Inputs:     a distance
07026     Returns     the number of brush object that will fit in the given distance
07027     Purpose:    as above
07028 
07029     SeeAlso:    -
07030 
07031 ********************************************************************************************/
07032 
07033 INT32 PathProcessorBrush::HowManyObjectsInDistance(MILLIPOINT Distance)
07034 {
07035     INT32 NumObjects = 0;
07036     MILLIPOINT DistanceSoFar = 0;
07037     MILLIPOINT Spacing = m_BrushSpacing;
07038 
07039     while (DistanceSoFar <= Distance)
07040     {
07041         NumObjects++;
07042         Spacing = (MILLIPOINT)(Spacing * m_BrushSpacingIncrProp);
07043         Spacing += m_BrushSpacingIncrConst;
07044         if (Spacing < MIN_BRUSH_SPACING)
07045             Spacing = MIN_BRUSH_SPACING;
07046         else 
07047         {
07048             if (Spacing > MAX_BRUSH_SPACING)
07049                     Spacing = MAX_BRUSH_SPACING;
07050         }
07051         DistanceSoFar += Spacing;
07052     }
07053     return NumObjects;
07054 }
07055 
07056 
07057 /********************************************************************************************
07058 
07059 >   BOOL PathProcessorBrush::IsThisPathProcessorOnTheStack(RenderRegion* pRender)
07060 
07061     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07062     Created:    29/8/2000
07063     Inputs:     pRender - the render region containing the path processor stack
07064     Returns     TRUE, if another path processor referring to the same brush definition as this one
07065                 is present on the stack, FALSE if not
07066     Purpose:    as above
07067 
07068     SeeAlso:    -
07069 
07070 ********************************************************************************************/
07071 
07072 BOOL PathProcessorBrush::IsThisPathProcessorOnTheStack(RenderRegion* pRender)
07073 {
07074     if (pRender == NULL)
07075     {
07076         ERROR3("Render Region is NULL in PathProcessorBrush::IsThisPathProcessorOnTheStack");
07077         return TRUE;  // for safety, as returning TRUE means we will probably not regenerate the brush
07078     }
07079 
07080     BOOL Retval = FALSE;
07081     PathProcessor* pPathProc = pRender->GetFirstPathProcessor();
07082 
07083     while (pPathProc != NULL)
07084     {
07085         // is it a brush?
07086         if (pPathProc->IsAPathProcessorBrush())
07087         {
07088             // is it our brush?
07089             if (((PathProcessorBrush*)pPathProc)->GetBrushDefinitionHandle() == m_BrushHandle)
07090             {
07091                 if (pPathProc != this)
07092                 {
07093                     Retval = TRUE;
07094                     break;
07095                 }
07096             }
07097         }
07098         pPathProc = pPathProc->GetNextProcessor();
07099     }
07100 
07101     return Retval;
07102 }
07103 
07104 /********************************************************************************************
07105 
07106 >   BOOL PathProcessorBrush::PrepareForRenderingLoop(UINT32 NumBrushObjects)
07107 
07108     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07109     Created:    3/10/2000
07110     Inputs:     NumBrushObjects - the number of brushrefs used by this brush
07111     Returns     TRUE if all went well
07112     Purpose:    Prepares the caches that we will use to store data about the transformations
07113                 performed during rendering.  Currently only scaling has been implemented but
07114                 we should also get rotation and tangential information too. This should be called 
07115                 sometime after calling Reset and before you start actually rendering
07116     SeeAlso:    -
07117 
07118 ********************************************************************************************/
07119 
07120 BOOL PathProcessorBrush::PrepareForRenderingLoop(UINT32 NumBrushObjects)
07121 {
07122     ERROR2IF(NumBrushObjects > MAX_BRUSH_OBJECTS, FALSE, "Too many objects in PathProcessorBrush::PrepareForRenderingLoop");
07123     ERROR2IF(NumBrushObjects == 0, FALSE, "No objects in PathProcessorBrush::PrepareForRenderingLoop");
07124 
07125     // make an array with a flag for each object which is set the first time it is rendered
07126     m_pObjectRendered = new BOOL[NumBrushObjects];
07127     if (m_pObjectRendered == NULL)
07128         return FALSE;
07129 
07130     // Initialise to false
07131     for (UINT32 i = 0; i < NumBrushObjects; i++)
07132         m_pObjectRendered[i] = FALSE;
07133 
07134     // make an array to hold the scaling values
07135     m_pLastScalingRendered = new double[NumBrushObjects];
07136     if (m_pLastScalingRendered == NULL)
07137     {
07138         delete m_pObjectRendered;
07139         m_pObjectRendered = NULL;
07140         return FALSE;
07141     }
07142 
07143     // initialise to our base scaling value
07144     for ( UINT32 i = 0; i < NumBrushObjects; i++)
07145         m_pLastScalingRendered[i] = m_BrushScaling;
07146 
07147     /*Special note:  As of 7/12/2000 only the Scaling cache is actually in use,
07148     m_pLastTangent = new double[NumBrushObjects];
07149     if (m_pLastTangent == NULL)
07150     {
07151         CleanUpAfterRender();
07152         return FALSE;
07153     }
07154     for (i = 0; i < NumBrushObjects; i++)
07155         m_pLastTangent[i] = 0.0;
07156 
07157     m_pLastRotation = new double[NumBrushObjects];
07158     if (m_pLastRotation == NULL)
07159     {
07160         CleanUpAfterRender();
07161         return FALSE;
07162     }
07163     for (i = 0; i < NumBrushObjects; i++)
07164         m_pLastRotation[i] = 0.0;
07165     */
07166     // we always want to use the actual scaling first time out
07167     m_UseActualScaling = TRUE; 
07168 
07169     return TRUE;
07170 }
07171 
07172 /********************************************************************************************
07173 
07174 >   void PathProcessorBrush::CleanUpAfterRender()
07175 
07176     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07177     Created:    3/10/2000
07178     Inputs:     -
07179     Returns     -
07180     Purpose:    deletes the caches that we used to store rendering data
07181     SeeAlso:    -
07182 
07183 ********************************************************************************************/
07184 
07185 void PathProcessorBrush::CleanUpAfterRender()
07186 {
07187     if (m_pObjectRendered != NULL)
07188     {
07189         delete m_pObjectRendered;
07190         m_pObjectRendered = NULL;
07191     }
07192     if (m_pLastScalingRendered != NULL)
07193     {
07194         delete m_pLastScalingRendered;
07195         m_pLastScalingRendered = NULL;
07196     }
07197     if (m_pLastTangent != NULL)
07198     {
07199         delete m_pLastTangent;
07200         m_pLastTangent = NULL;
07201     }
07202     if (m_pLastRotation != NULL)
07203     {
07204         delete m_pLastRotation;
07205         m_pLastRotation = NULL;
07206     }
07207 }
07208 
07209 
07210 /********************************************************************************************
07211 
07212 >   BOOL PathProcessorBrush::SetLastRenderedData(UINT32 BrushObject, double Scaling, double Tangent, 
07213                                              double Rotation)
07214 
07215     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07216     Created:    3/10/2000
07217     Inputs:     NumBrushObjects - the brush object last rendered
07218                 Scaling - the scaling we last used to render
07219                 Tangent - the tangent we last used to render
07220                 Rotation - the last rotation etc.
07221     Returns     TRUE if all went well
07222     Purpose:    Should be called to update the caches that store our cached transformation data
07223                 so that we only have to perform changes in transformations.
07224                 Currently only OpDrawBrush need call this as the normal path processor rendering
07225                 loop updates itself, though this may change.
07226                 Note also that the rotation and tangent data are not yet used.
07227     SeeAlso:    -
07228 
07229 ********************************************************************************************/
07230 
07231 BOOL PathProcessorBrush::SetLastRenderedData(UINT32 BrushObject, double Scaling, double Tangent, 
07232                                              double Rotation)
07233 {
07234     ERROR2IF(m_pObjectRendered == NULL || m_pLastScalingRendered == NULL ||
07235              m_pLastTangent == NULL || m_pLastRotation == NULL, FALSE, "Data caches have not been initialised in PathProcessorBrush::SetLastRenderedData");
07236 
07237 
07238 #ifdef _DEBUG
07239     if (BrushObject > GetNumBrushObjects())
07240     {
07241         ERROR3("Object index out of bounds in PathProcessorBrush::SetLastRenderedData");
07242         return FALSE;
07243     }
07244     
07245 #endif
07246     m_pObjectRendered[BrushObject] = TRUE;
07247     m_pLastScalingRendered[BrushObject] = Scaling;
07248     m_pLastTangent[BrushObject] = Tangent;
07249     m_pLastRotation[BrushObject] = Rotation;
07250 
07251     m_LastScalingRendered = Scaling;
07252 
07253     return TRUE;            
07254 }
07255 
07256 
07257 /********************************************************************************************
07258 
07259 >   void PathProcessorBrush::DecideWhetherToUseActualScaling(UINT32 BrushObject)
07260 
07261     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07262     Created:    3/10/2000
07263     Inputs:     NumBrushObjects - the brush object last rendered
07264             
07265 
07266     Purpose:    Decides whether or not to set the UseActualScaling flag for the next call of
07267                 GetNextScaling.  Basically if we have not rendered this object before then the
07268                 scaling we wish to use will be the absolute scaling.  However subsequently we only
07269                 wish to know about scaling changes.
07270                 This function is called by OpDrawBrush::RenderStepsForTime, and ProcessPath.
07271                 
07272     SeeAlso:    -
07273 
07274 ********************************************************************************************/
07275 
07276 void PathProcessorBrush::DecideWhetherToUseActualScaling(UINT32 BrushObject)
07277 {
07278     if  (m_pObjectRendered == NULL || m_pLastScalingRendered == NULL)
07279     {
07280         ERROR3("Data caches have not been initialised in PathProcessorBrush::DecideWhetherToUseActualScaling");
07281         return;
07282     }
07283              
07284 
07285 
07286 //#ifdef _DEBUG
07287     if (BrushObject >= GetNumBrushObjects())
07288     {
07289         ERROR3("Object index out of bounds in PathProcessorBrush::SetLastRenderedData");
07290         return;
07291     }
07292     
07293 //#endif
07294 
07295     if (m_pObjectRendered[BrushObject])
07296     {
07297         m_UseActualScaling = FALSE;
07298         m_LastScalingRendered = m_pLastScalingRendered[BrushObject];
07299     }
07300     else
07301     {
07302         m_UseActualScaling = TRUE;
07303     }
07304 // Phil, 14/01/2004 this change accompanies the rewritten RenderBrushAtPoint function
07305 // This routine was a bodge because RenderBrushAtPoint used to permanently affect the size (scale)
07306 // of the brush path definitions!!! ARGH!
07307 // The new routine leave path definitions untouched.
07308 #ifdef NEW_RENDERBRUSHATPOINT
07309     m_UseActualScaling = TRUE;
07310 #endif
07311 
07312 }
07313 
07314 
07315 /********************************************************************************************
07316 
07317 >   void PathProcessorBrush::SetStrokeColour(DocColour Col)
07318 
07319     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07320     Created:    3/10/2000
07321     Inputs:     Col - the stroke colour to use
07322     Returns     -
07323     Purpose:    if the brush is overriding colours then this function can be used to set the
07324                 stroke colour to use.  Although this will be set automatically in ProcessPath.
07325                 Mostly for use by OpDrawBrush
07326     SeeAlso:    -
07327 
07328 ********************************************************************************************/
07329 
07330 void PathProcessorBrush::SetStrokeColour(DocColour Col)
07331 {
07332     m_CurrentStrokeCol = Col;   
07333 }
07334 
07335 /********************************************************************************************
07336 
07337 
07338 >   BOOL PathProcessorBrush::WriteNative(BaseCamelotFilter *pFilter)
07339 
07340     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
07341     Created:    13/12/99
07342 
07343     Inputs:     pFilter - filter to write to
07344 
07345     Returns:    TRUE if the Node has written out a record to the filter
07346 
07347     Purpose:    Writes out a record that represents the processor, to either Native or Web
07348                 file format
07349 
07350     Notes:      Brush details are written out in two places, here and in the brush component.
07351                 This records details of an individual brush in a document, details of the actual
07352                 ink nodes used to generate the brush are recorded in the brush component.
07353                 
07354 
07355     SeeAlso:    AttrBrushType::WritePreChildrenNative; BrushAttrRecordHandler::HandleRecord
07356 
07357 ********************************************************************************************/
07358 
07359 
07360 BOOL PathProcessorBrush::WriteNative(BaseCamelotFilter *pFilter)
07361 {
07362     ERROR3IF(pFilter == NULL, "Illegal NULL param");
07363     
07364     CXaraFileRecord Record(TAG_BRUSHATTR, TAG_BRUSHATTR_SIZE);
07365     BOOL ok = Record.Init();
07366     
07367     BYTE Flags = 0;
07368     if (m_bTile) 
07369         Flags |= TAG_BRUSHTILE_FLAG;
07370     if (m_bRotate)
07371         Flags |= TAG_BRUSHROTATE_FLAG;
07372 
07373 //  INT32 Offset = (INT32)m_PathOffsetType;
07374 
07375     if (ok) ok = Record.WriteUINT32(m_BrushHandle);
07376     if (ok) ok = Record.WriteINT32(m_BrushSpacing);
07377     if (ok) ok = Record.WriteBYTE(Flags);
07378     if (ok) ok = Record.WriteDOUBLE(m_RotateAngle);
07379     if (ok) ok = Record.WriteINT32(m_PathOffsetType);
07380     if (ok) ok = Record.WriteINT32(m_PathOffsetValue);
07381     if (ok) ok = Record.WriteDOUBLE(m_BrushScaling);
07382     if (ok) ok = pFilter->Write(&Record);
07383 
07384     CXaraFileRecord NextRec(TAG_MOREBRUSHATTR, TAG_MOREBRUSHATTR_SIZE);
07385     if (ok) ok = NextRec.Init();
07386     if (ok) ok = NextRec.WriteDOUBLE(m_BrushSpacingIncrProp);
07387     if (ok) ok = NextRec.WriteINT32(m_BrushSpacingIncrConst);
07388     if (ok) ok = NextRec.WriteINT32((INT32)m_BrushSpacingMaxRand);
07389     if (ok) ok = NextRec.WriteINT32((INT32)m_BrushSpacingRandSeed);
07390 
07391     if (ok) ok = NextRec.WriteDOUBLE(m_BrushScalingIncr);
07392     if (ok) ok = NextRec.WriteINT32((INT32)m_BrushScalingMaxRand);
07393     if (ok) ok = NextRec.WriteINT32((INT32)m_BrushScalingRandSeed);
07394 
07395     if (ok) ok = NextRec.WriteINT32((INT32)m_SequenceType);
07396     if (ok) ok = NextRec.WriteINT32((INT32)m_SequenceRandSeed);
07397 
07398     if (ok) ok = NextRec.WriteDOUBLE(m_PathOffsetIncrProp);
07399     if (ok) ok = NextRec.WriteINT32(m_PathOffsetIncrConst);
07400     if (ok) ok = NextRec.WriteINT32((INT32)m_OffsetTypeRandSeed);
07401     if (ok) ok = NextRec.WriteINT32((INT32)m_OffsetValueMaxRand);
07402     if (ok) ok = NextRec.WriteINT32((INT32)m_OffsetValueRandSeed);
07403     INT32 UseFill = m_bUseLocalFillColour ? 1234 : 0;
07404     if (ok) ok = NextRec.WriteINT32(UseFill);
07405 
07406     if (ok) ok = pFilter->Write(&NextRec);
07407 
07408     CXaraFileRecord AnotherRec(TAG_EVENMOREBRUSHATTR, TAG_EVENMOREBRUSHATTR_SIZE);
07409     if (ok) ok = AnotherRec.Init();
07410     if (ok) ok = AnotherRec.WriteINT32((INT32)m_RotationMaxRand);
07411     if (ok) ok = AnotherRec.WriteINT32((INT32)m_RotationRandSeed);
07412     BYTE ScaleFlag = 0;
07413     ScaleFlag |= TAG_SCALETOWIDTH_FLAG;
07414     if (ok) ok = AnotherRec.WriteBYTE(ScaleFlag);
07415     if (ok) ok = pFilter->Write(&AnotherRec);
07416 
07417     // write the fill flags out
07418     CXaraFileRecord FillRec(TAG_BRUSHATTRFILLFLAGS, TAG_BRUSHATTRFILLFLAGS_SIZE);
07419     if (ok) ok = FillRec.Init();
07420     BYTE FillFlags = 0;
07421     if (m_bUseLocalFillColour)
07422         FillFlags |= BRUSHFILLFLAG_LOCALFILL;
07423 
07424     if (m_bUseLocalTransp)
07425         FillFlags |= BRUSHFILLFLAG_LOCALTRANSP;
07426 
07427     if (m_bUseNamedColours)
07428         FillFlags |= BRUSHFILLFLAG_NAMEDCOL;
07429 
07430     if (ok) ok = FillRec.WriteBYTE(FillFlags);
07431     if (ok) ok = pFilter->Write(&FillRec);
07432     
07433     // write the pressure info
07434     CXaraFileRecord PressureRec(TAG_BRUSHATTRPRESSUREINFO, TAG_BRUSHATTRPRESSUREINFO_SIZE);
07435     if (ok) ok = PressureRec.Init();
07436     if (ok) ok = PressureRec.WriteINT32((INT32)m_ScalingMaxPressure);
07437     if (ok) ok = PressureRec.WriteINT32((INT32)m_SpacingMaxPressure);
07438     if (ok) ok = PressureRec.WriteINT32((INT32)m_OffsetMaxPressure);
07439     if (ok) ok = PressureRec.WriteINT32((INT32)m_RotationMaxPressure);
07440     if (ok) ok = PressureRec.WriteINT32((INT32)m_HueMaxPressure);
07441     if (ok) ok = PressureRec.WriteINT32((INT32)m_SatMaxPressure);
07442     if (ok) ok = PressureRec.WriteINT32((INT32)m_TimeStampMaxPressure);
07443     if (ok) ok = pFilter->Write(&PressureRec);
07444 
07445     // write the transparency data - plus a few other things I forget elsewhere
07446     CXaraFileRecord TranspRec(TAG_BRUSHATTRTRANSPINFO, TAG_BRUSHATTRTRANSPINFO_SIZE);
07447     if (ok) ok = TranspRec.Init();
07448     if (ok) ok = TranspRec.WriteINT32(m_BrushTransparency);
07449     if (ok) ok = TranspRec.WriteINT32(INT32(m_TranspMaxPressure));
07450     if (ok) ok = TranspRec.WriteDOUBLE(m_RotAngleIncrConst);
07451     if (ok) ok = TranspRec.WriteDOUBLE(m_BrushScalingIncrConst);
07452     if (ok) ok = TranspRec.WriteINT32(INT32(m_BrushHueMaxRand));
07453     if (ok) ok = TranspRec.WriteINT32(INT32(m_BrushHueRandSeed));
07454     if (ok) ok = TranspRec.WriteINT32(INT32(m_BrushSatMaxRand));
07455     if (ok) ok = TranspRec.WriteINT32(INT32(m_BrushSatRandSeed));
07456     
07457     if (ok) ok = pFilter->Write(&TranspRec);
07458 
07459     // recall that the timestamping data and the pressure data belong to
07460     // the attribute so they are written out there
07461 
07462     return ok;
07463 }

Generated on Sat Nov 10 03:46:33 2007 for Camelot by  doxygen 1.4.4