cmxdcobj.cpp

Go to the documentation of this file.
00001 // $Id: cmxdcobj.cpp 1282 2006-06-09 09:46:49Z 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 // CMXExportDC object output routines
00099 
00100 #include "camtypes.h"
00101 #include "cmxexdc.h"
00102 #include "cmxrendr.h"
00103 #include "cmxform.h"
00104 //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 #include "colcontx.h"
00108 //#include "nev.h"
00109 //#include "cmxres.h"
00110 #include "fillramp.h"
00111 
00112 
00113 /********************************************************************************************
00114 
00115 >   BOOL CMXExportDC::WriteBlankAttributes(INT32 Tag)
00116 
00117     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00118     Created:    16/07/96
00119     Inputs:     render region
00120     Returns:    success
00121     Purpose:    writes a blank attribute tag and contents, which specifies nothing but
00122                 keeps everything happy
00123 
00124 ********************************************************************************************/
00125 
00126 BOOL CMXExportDC::WriteBlankAttributes(INT32 Tag)
00127 {
00128     // start the tag
00129     if(Tag != -1)
00130         if(!StartTag(Tag))
00131             return FALSE;
00132 
00133     // write the attribute mask thingy
00134     WriteByte(0);
00135 
00136     // end the tag
00137     if(Tag != -1)
00138         if(!EndTag())
00139             return FALSE;
00140     
00141     return TRUE;
00142 }
00143 
00144 
00145 /********************************************************************************************
00146 
00147 >   BOOL CMXExportDC::WriteAttributes(CMXRenderRegion *pReg, INT32 Tag, DocCoord *Coords, INT32 NumCoords, BOOL ForceNoFill = FALSE)
00148 
00149     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00150     Created:    01/07/96
00151     Inputs:     render region
00152     Returns:    success
00153     Purpose:    Writes the attributes to the DC.
00154                 if ForceNoFill == TRUE, the path will not be filled whatever the colour
00155 
00156 ********************************************************************************************/
00157 
00158 BOOL CMXExportDC::WriteAttributes(CMXRenderRegion *pReg, INT32 Tag, DocCoord *Coords, INT32 NumCoords, BOOL ForceNoFill)
00159 {
00160     // give lenses a chance
00161     BOOL WasLens = FALSE;
00162     if(!WriteAttrCheckLens(pReg, Tag, Coords, NumCoords, &WasLens))
00163         return FALSE;
00164 
00165     // now did the lens checking bit output something?
00166     if(WasLens)
00167         return TRUE;        // yep, so we don't want to output them too
00168 
00169     // start the tag
00170     if(Tag != -1)
00171         if(!StartTag(Tag))
00172             return FALSE;
00173 
00174     // write the attribute mask thingy
00175     WriteByte((ForceNoFill?0:cmxRENDATTRMASK_FILL) | cmxRENDATTRMASK_OUTLINE);
00176 
00177     // write the fill specification
00178     if(!ForceNoFill)
00179         if(!WriteFillSpec(pReg, Coords, NumCoords, ForceNoFill))
00180             return FALSE;
00181 
00182     // write the outline specification
00183     if(!WriteOutlineSpec(pReg))
00184         return FALSE;
00185 
00186     // end the tag
00187     if(Tag != -1)
00188         if(!EndTag())
00189             return FALSE;
00190     
00191     return TRUE;
00192 }
00193 
00194 
00195 /********************************************************************************************
00196 
00197 >   BOOL CMXExportDC::WriteFillType(WORD FillID)
00198 
00199     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00200     Created:    04/07/96
00201     Inputs:     fill type
00202     Returns:    success
00203     Purpose:    Writes the fill type to the DC
00204 
00205 ********************************************************************************************/
00206 
00207 BOOL CMXExportDC::WriteFillType(WORD FillID)
00208 {
00209     ExportFile->write(&FillID, sizeof(FillID));
00210 
00211     return TRUE;
00212 }
00213 
00214 
00215 /********************************************************************************************
00216 
00217 >   BOOL CMXExportDC::WriteFillSpec(CMXRenderRegion *pReg)
00218 
00219     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00220     Created:    04/07/96
00221     Inputs:     render region
00222     Returns:    success
00223     Purpose:    Writes the fill specifcation to the DC
00224 
00225 ********************************************************************************************/
00226 
00227 BOOL CMXExportDC::WriteFillSpec(CMXRenderRegion *pReg, DocCoord *Coords, INT32 NumCoords, BOOL NoFill)
00228 {
00229     // tag the start
00230     if(!StartNestedTag(cmxTAG_RenderAttr_FillSpec))
00231         return FALSE;
00232 
00233     if(NoFill)
00234     {
00235         if(!WriteFillType(cmxFILLID_NONE))
00236             return FALSE;
00237     }
00238     else
00239     {
00240         // get the attribute
00241         FillGeometryAttribute *pFillGeometry
00242                 = (FillGeometryAttribute *)pReg->GetCurrentAttribute(ATTR_FILLGEOMETRY);
00243 
00244         // check it out
00245         ERROR2IF(pFillGeometry == 0, FALSE, "No fill geometry");
00246         ERROR3IF(!pFillGeometry->IsKindOf(CC_RUNTIME_CLASS(FillGeometryAttribute)), "not one of them there fill geometries");
00247 
00248         // right then, decide what to do with the thingy
00249         if(pFillGeometry->IsAFlatFill())
00250         {
00251             // flat fill -- check to see if it's transparent
00252             DocColour *pCol = pFillGeometry->GetStartColour();
00253             ERROR2IF(pCol == NULL, FALSE, "not one of your earth colours");
00254             if(pCol->IsTransparent())
00255             {
00256                 // it's transparent, write no fill
00257                 if(!WriteFillType(cmxFILLID_NONE))
00258                     return FALSE;
00259             }
00260             else
00261             {
00262                 // it's OK, it is. Write it.
00263                 if(!WriteFillType(cmxFILLID_UNIFORM)
00264                     || !WriteFillSpecFlat(pReg, pFillGeometry))
00265                     return FALSE;
00266             }
00267         }
00268         else if(pFillGeometry->IsAKindOfBitmapFill())
00269         {
00270             // bitmap type fill -- do nothing for now
00271             if(!WriteFillType(9) //cmxFILLID_COLPATTERN)
00272                 || !WriteFillSpecBitmap(pReg, pFillGeometry, Coords, NumCoords))
00273                 return FALSE;
00274         }
00275         else if(pFillGeometry->IsAGradFill())
00276         {
00277             // grad fill
00278             if(!WriteFillType(cmxFILLID_FOUNTAIN)
00279                 || !WriteFillSpecGrad(pReg, pFillGeometry, Coords, NumCoords))
00280                 return FALSE;
00281         }
00282         else
00283         {
00284             // catch all -- write a no fill thingy
00285             if(!WriteFillType(cmxFILLID_NONE))
00286                 return FALSE;
00287         }
00288     }
00289 
00290     // end the tag
00291     if(!EndNestedTag())
00292         return FALSE;
00293     
00294     // write the end tag
00295     if(!WriteMinEndTag())
00296         return FALSE;
00297 
00298     return TRUE;
00299 }
00300 
00301 /********************************************************************************************
00302 
00303 >   BOOL CMXExportDC::WriteFillSpecFlat(CMXRenderRegion *pReg, FillGeometryAttribute *pFill)
00304 
00305     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00306     Created:    04/07/96
00307     Inputs:     render region
00308     Returns:    success
00309     Purpose:    Writes the flat fill specifcation to the DC
00310 
00311 ********************************************************************************************/
00312 
00313 BOOL CMXExportDC::WriteFillSpecFlat(CMXRenderRegion *pReg, FillGeometryAttribute *pFill)
00314 {
00315     // get the colour
00316     DocColour *pFillColour = pFill->GetStartColour();
00317     ERROR2IF(pFillColour == NULL, FALSE, "Wibble. No fill colour on this here flat fill");
00318 
00319     // find a reference for it
00320     WORD FillReference = GetColourReference(pFillColour);
00321 
00322     // write some stuff
00323     struct {
00324         WORD FillReference;
00325         WORD ScreenReference;
00326     } filldef = {FillReference, cmxSCREENREFERENCE};
00327 
00328     if(!WriteNestedTag(cmxTAG_RenderAttr_FillSpec_Uniform, &filldef, sizeof(filldef))
00329         || !WriteMinEndTag())
00330         return FALSE;
00331 
00332     return TRUE;
00333 }
00334 
00335 
00336 /********************************************************************************************
00337 
00338 >   BOOL CMXExportDC::WriteFillSpecGrad ( CMXRenderRegion *pReg,
00339                                           FillGeometryAttribute *pFill,
00340                                           DocCoord *Coords,
00341                                           INT32 NumCoords )
00342 
00343     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00344     Created:    10/07/96
00345     Inputs:     render region
00346     Returns:    success
00347     Purpose:    Writes the grad fill specifcation to the DC
00348 
00349 ********************************************************************************************/
00350 
00351 BOOL CMXExportDC::WriteFillSpecGrad ( CMXRenderRegion *pReg,
00352                                       FillGeometryAttribute *pFill,
00353                                       DocCoord *Coords,
00354                                       INT32 NumCoords )
00355 {
00356     DocColour   StartColour;                // The first colour in the fill.
00357     DocColour   EndColour;                  // The end colour of the fill.
00358     DocColour   MidColour;                  // Only used to approximate four colour fills.
00359     BOOL        Radial          = FALSE;    // Is it a radial fill?
00360     BOOL        FourColour      = FALSE;    // Is it a four colour fill?
00361 
00362     // is this a radial type derivative?
00363     if ( pFill->IsARadialFill () )
00364     {
00365         // We need to swap the colours over as Corel has a different idea
00366         // of start and finish colours to Camelot.
00367         StartColour = *( pFill->GetEndColour () );
00368         EndColour   = *( pFill->GetStartColour () );
00369 
00370         Radial = TRUE;
00371     }
00372     else if ( pFill->IsAConicalFill () || pFill->IsASquareFill () )
00373     {
00374         // Set up the colour values.
00375         StartColour = *( pFill->GetStartColour () );
00376         EndColour   = *( pFill->GetEndColour () );
00377 
00378         Radial = TRUE;
00379     }
00380     else if ( pFill->IsAFourColFill () )
00381     {
00382         // Set up the start and end colours as usual, but create a third colour value to
00383         // help fake the four colour fill.
00384         StartColour = *( pFill->GetStartColour () );
00385         EndColour   = *( pFill->GetEndColour3 () );
00386         MidColour.Mix ( pFill->GetEndColour (), pFill->GetEndColour2 (), 0.5f, NULL, FALSE, NULL );
00387 
00388         // Reset the four colour flag.
00389         FourColour  = TRUE;
00390     }
00391     else if ( pFill->IsAThreeColFill () )
00392     {
00393         // Set up the colour values. I'm blending the colours of the two endpoints
00394         // to get a better approximation of a three colour fill.
00395         StartColour = *( pFill->GetStartColour () );
00396         EndColour.Mix ( pFill->GetEndColour (), pFill->GetEndColour2 (), 0.5f, NULL, FALSE, NULL );
00397     }
00398     else
00399     {
00400         // Default behaviour: Store the start and end colours.
00401         StartColour = *( pFill->GetStartColour () );
00402         EndColour   = *( pFill->GetEndColour () );
00403     }
00404 
00405     // Find references for the color, and sort out the fill effect.
00406     WORD    StartColReference   = GetColourReference ( &StartColour );
00407     WORD    EndColReference     = GetColourReference ( &EndColour );
00408     WORD    MidColReference     = 0;
00409     WORD    FillMode            = cmxFILLMODE_RGB;
00410 
00411     // Get a colour reference to MidColour if it's been declared. (i.e. the fill is a
00412     // four colour fill.)
00413     if ( FourColour )
00414     {
00415         MidColReference = GetColourReference ( &MidColour );
00416     }
00417 
00418     // get the fill effect attribute
00419     FillEffectAttribute *pFillEff =
00420         (FillEffectAttribute *)pReg->GetCurrentAttribute(ATTR_FILLEFFECT);
00421     ERROR2IF(pFillEff == NULL || !pFillEff->IsKindOf(CC_RUNTIME_CLASS(FillEffectAttribute)), FALSE, "not a fill effect");
00422     BOOL Rainbow = FALSE, Alt = FALSE;
00423     if(IS_A(pFillEff, FillEffectRainbowAttribute))
00424         Rainbow = TRUE;
00425     if(IS_A(pFillEff, FillEffectAltRainbowAttribute))
00426         Rainbow = Alt = TRUE;
00427 
00428     if(Rainbow)
00429     {
00430         // right, we need to work out which direction we want the colour to go
00431         // around the HSV colour wheel. Convert both colours to HSV.
00432         ColourContext *Conv = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
00433 
00434         ColourHSVT StartC;
00435         ColourHSVT EndC;
00436 
00437         Conv->ConvertColour( &StartColour, (ColourGeneric *)&StartC);
00438         Conv->ConvertColour( &EndColour, (ColourGeneric *)&EndC);
00439 
00440         // compare the hues and work out a difference
00441         double Difference = (EndC.Hue.MakeDouble()) - (StartC.Hue.MakeDouble());
00442 
00443         BOOL ClockWise = (Difference < 0);
00444 
00445         if(fabs(Difference) >= 0.5)
00446             ClockWise = !ClockWise;
00447 
00448         if(Alt = TRUE)
00449             ClockWise = !ClockWise;
00450         
00451         // set the correct thingy attribute
00452         if(ClockWise)
00453             FillMode = cmxFILLMODE_HSB_CW;
00454         else
00455             FillMode = cmxFILLMODE_HSB_CCW;
00456     }
00457 
00458     // find the start and end coords of the fill
00459     DocCoord StartPoint = *( pFill->GetStartPoint() );
00460     DocCoord EndPoint;
00461 
00462     // Graeme (18-2-00) - Modifications to handle three and four colour fills better.
00463     if ( pFill->IsAFourColFill () )
00464     {
00465         // Use EndPoint3 to get a diagonal across the bounding box.
00466         EndPoint = *( pFill->GetEndPoint3 () );
00467     }
00468     else if ( pFill->IsAThreeColFill () )
00469     {
00470         // Merge the existing two endpoints to get the correct endpoint for the fill.
00471         EndPoint = *( pFill->GetEndPoint () ) +
00472                    *( pFill->GetEndPoint2 () ) -
00473                    *( pFill->GetStartPoint () );
00474     }
00475     else
00476     {
00477         // Default: Use the standard endpoint.
00478         EndPoint = *( pFill->GetEndPoint () );
00479     }
00480 
00481 
00482     // find the corel bounding box of the path we're about to fiddle with
00483     DocRect cBBox;
00484     CalcCorelBBox(Coords, NumCoords, &cBBox);
00485 
00486     // run the chicken out clause for extreme cases I can't be bothered to handle
00487     if ( StartPoint == EndPoint || cBBox.Width () == 0 || cBBox.Height () == 0 )
00488         return WriteFillSpecFlat(pReg, pFill);
00489 
00490     // calc the central coord
00491     DocCoord Centre;
00492     Centre.x = cBBox.lo.x + cBBox.Width() / 2;
00493     Centre.y = cBBox.lo.y + cBBox.Height() / 2;
00494 
00495     // calc the fill parameters
00496 
00497     // first work out the distance between the start and end points
00498     double dx = EndPoint.x - StartPoint.x;
00499     double dy = EndPoint.y - StartPoint.y;
00500     double PointDist = sqrt(((dx * dx) + (dy * dy)));
00501 
00502     // now we need to work out the angle of the fill
00503     double Angle = atan2(dy, dx);
00504         // atan2 is defined if dx == 0
00505         // but not at the origin -- however we've filtered out this case
00506 
00507     INT32 StartPercent;
00508     INT32 EndPercent;
00509 
00510     cmxFillBase1 fb1;
00511     fb1.Padding = 0;
00512     cmxFillBase2 fb2;
00513     fb2.XOffset = 0;
00514     fb2.YOffset = 0;
00515 
00516     if(Radial)
00517     {
00518         //------------------------------------------------- radial type fill calucations
00519 
00520         // ...and for my first trick, I will calculate the X and Y
00521         // offsets of the centre of this fill
00522         DocCoord dCentre = StartPoint - Centre;
00523         fb2.XOffset = (dCentre.x * 100) / cBBox.Width();
00524         fb2.YOffset = (dCentre.y * 100) / cBBox.Height();
00525         // get these values within the required range
00526         if(fb2.XOffset > 100) fb2.XOffset = 100;
00527         if(fb2.XOffset < -100) fb2.XOffset = -100;
00528         if(fb2.YOffset > 100) fb2.YOffset = 100;
00529         if(fb2.YOffset < -100) fb2.YOffset = -100;
00530 
00531         // now this is the scary bit. Corel use a complex method for specifing
00532         // their radial type fills. 
00533         double w = cBBox.Width(), h = cBBox.Height();
00534         double bboxdiagonal = sqrt(w*w + h*h);
00535         double cdx = dCentre.x, cdy = dCentre.y;
00536         double cendist = sqrt(cdx*cdx + cdy*cdy);
00537         double BodgeFactor = 1 + (cendist / (bboxdiagonal / 2));
00538         double targetradius = PointDist / BodgeFactor;
00539         double Pad = 50 * (1 - (2 * targetradius) / bboxdiagonal);
00540         // munge the Pad value to the allowed range
00541         if(Pad < 0) Pad = 0;
00542         if(Pad > 44) Pad = 44;
00543         // and bung in the structure for export
00544         fb1.Padding = (WORD)Pad;
00545 
00546         // set the percentages to 0
00547         StartPercent = 0;
00548         EndPercent = 0;
00549 
00550         // if it's a square fill, swap the colours over
00551         if(pFill->IsASquareFill())
00552         {
00553             WORD t = StartColReference;
00554             StartColReference = EndColReference;
00555             EndColReference = t;
00556         }
00557     } // if ( Radial )
00558 
00559     else // if ( !Radial )
00560     {
00561         //------------------------------------------------- linear type fill calucations
00562 
00563         // now work out the coords of the intersection of a line through the
00564         // centre of the bbox and the edges of the bbox
00565 
00566         // right then, we want the angle within 0 and PI/2
00567         double cAngle = Angle;
00568         INT32 cAR = 0;
00569         while(cAngle > (PI/2))
00570         {
00571             cAngle -= PI/2;
00572             cAR++;
00573         }
00574 
00575         // luckily, everything is symmetrical so all we need do is calc the
00576         // intersect in the top quadrant.
00577         INT32 qdx = cBBox.Width() / 2;
00578         INT32 qdy = cBBox.Height() / 2;
00579         if((cAR & 1) != 0)
00580         {
00581             // we rotated by an odd multiple of PI/2 radians. Rotate the box as well.
00582             INT32 t = qdy;
00583             qdy = qdx;
00584             qdx = t;
00585         }
00586         DocCoord i;
00587         if(qdy == 0)
00588         {
00589             // special case to avoid division by tan(0) = 0
00590             i.x = qdx;
00591             i.y = 0;
00592         }
00593         else
00594         {
00595             double predqdy = qdx * tan(cAngle);
00596             if(predqdy > qdy)
00597             {
00598                 // intersects on the horizontal
00599                 i.x = (INT32)(((double)qdy) / tan(cAngle));
00600                 i.y = qdy;
00601             }
00602             else
00603             {
00604                 // intersects on the vertical
00605                 i.x = qdx;
00606                 i.y = (INT32)(((double)qdx) * tan(cAngle));
00607             }
00608         }
00609 
00610         // i is the offset from the centre of the bbox where the line of the
00611         // grad fill rotated to the top right quadrent intersects with the
00612         // rectange of the bounding box.
00613 
00614         // now we need to work out the percentages along this line of the start
00615         // and stop bit.
00616         INT32 linelength = (INT32)sqrt(((double)(i.x) * (double)(i.x)) + ((double)(i.y) * (double)(i.y)));
00617         // chicken out clause #2
00618         if(linelength == 0)
00619             return WriteFillSpecFlat(pReg, pFill);
00620 
00621         // work out the start and end points as offsets from the centre point
00622         DocCoord    dStartPoint = StartPoint - Centre;
00623         DocCoord    dEndPoint   = EndPoint - Centre;
00624 
00625         // rotate these points around the origin
00626         // TODO: do the rotation myself, instead of going through matrices
00627         Matrix Mat(((- Angle) * 360.0) / (2*PI));   // why can't people use proper measure? 
00628         Mat.transform(&dStartPoint);
00629         Mat.transform(&dEndPoint);
00630 
00631         // find out the smallest distance from the end of the line
00632         INT32 dStart = dStartPoint.x + linelength;
00633         INT32 dEnd = linelength - dEndPoint.x;
00634         if(dStart < 0) dStart = 0;
00635         if(dEnd < 0) dEnd = 0;
00636         INT32 dPad;     // smallest of dStart and dEnd
00637         if(dStart < dEnd)
00638             dPad = dStart;
00639         else
00640             dPad = dEnd;
00641 
00642         INT32 padval = (dPad * 100) / (linelength * 2);
00643         if(padval < 0) padval = 0;
00644         if(padval > 44) padval = 44;
00645         fb1.Padding = (WORD)padval;
00646         
00647         // right, now munge the line length value to take account of this padding
00648         linelength -= dPad;
00649 
00650         // right then, we can now simply compare the x coords of the start and end
00651         // with the linelength above to find the start and end percentages
00652         StartPercent = (INT32)((dStartPoint.x + linelength) * 100);
00653         EndPercent = (INT32)((dEndPoint.x + linelength) * 100);
00654         StartPercent /= (linelength * 2);
00655         EndPercent /= (linelength * 2);
00656 
00657         // sanity check the numbers so Corel is happy
00658         if(StartPercent < 0) StartPercent = 0;
00659         if(StartPercent > 100) StartPercent = 100;
00660         if(EndPercent < 0) EndPercent = 0;
00661         if(EndPercent > 100) EndPercent = 100;
00662         if(EndPercent < StartPercent)
00663         {
00664             INT32 t = StartPercent;
00665             StartPercent = EndPercent;
00666             EndPercent = t;
00667         }
00668     } // else if ( !Radial )
00669 
00670     // I allege we now know enough to get this thing to the file
00671     // start the tag
00672     if(!StartNestedTag(cmxTAG_RenderAttr_FillSpec_Fountain_Base))
00673         return FALSE;
00674 
00675     if(pFill->IsARadialFill())
00676         fb1.Type = cmxFOUNTAINTYPE_RADIAL;
00677     else if(pFill->IsASquareFill())
00678         fb1.Type = cmxFOUNTAINTYPE_SQUARE;
00679     else if(pFill->IsAConicalFill())
00680         fb1.Type = cmxFOUNTAINTYPE_CONICAL;
00681     else
00682         fb1.Type = cmxFOUNTAINTYPE_LINEAR;
00683     fb1.Screen = cmxSCREENREFERENCE;
00684     // padding set earlier
00685 
00686     // offsets set earlier
00687     fb2.StepCount = 0;
00688     fb2.FillMode = FillMode;
00689     fb2.RateMethod = 0;
00690     fb2.RateValue = 50;         // 50% is the centre, a commonly held belief
00691 
00692     if(!Radial)
00693     {
00694         if(FillMode == cmxFILLMODE_RGB)
00695         {
00696             // if it's an RGB mix in a linear fill, we can accurately
00697             // specify the fill by using a custom fill mode, and specifing
00698             // the end points presicely.
00699             fb2.FillMode = cmxFILLMODE_CUSTOM;
00700         }
00701         else
00702         {
00703             // if it's not an RGB mix, we need to approximate the fill using the
00704             // padding (set already) as we can't specify where we want the
00705             // colours to start and finish along the line of the fill
00706             StartPercent = 0;
00707             EndPercent = 0;
00708         }
00709     }
00710 
00711     // write the data
00712     ExportFile->write(&fb1, sizeof(fb1));
00713 
00714     WriteAngle(Angle);
00715 
00716     if(ThirtyTwoBit)
00717     {
00718         ExportFile->write(&fb2, sizeof(fb2));
00719     }
00720     else
00721     {
00722         // OK, so this way is a bit of a bodge
00723         cmxFillBase2_16 b = {0, (SWORD)fb2.XOffset, (SWORD)fb2.YOffset,
00724             fb2.StepCount, fb2.FillMode};
00725 
00726         ExportFile->write(&b, sizeof(b));
00727     }
00728 
00729     // end the tag
00730     if(!EndNestedTag())
00731         return FALSE;
00732 
00733     // write the colours
00734     if(!StartNestedTag(cmxTAG_RenderAttr_FillSpec_Fountain_Color))
00735         return FALSE;
00736 
00737     cmxGradFillColour   col;
00738     ColourRamp          *pRamp  = pFill->GetColourRamp ();
00739     WORD                NCol    = 2 + ( ( StartPercent != 0 ) ? 1 : 0 ) +
00740                                   ( ( EndPercent != 100 ) ? 1 : 0 ) + ( FourColour ? 1 : 0 );
00741 
00742     // If the fill has a colour ramp, calculate the number of entries within it.
00743     if ( pRamp != NULL )
00744     {
00745         UINT32  FirstIndex  = 0;
00746         UINT32  LastIndex   = 0;
00747 
00748         // Call a member function to get the indices to the first and last elements within
00749         // the colour ramp.
00750         pRamp->GetIndexRange ( &FirstIndex, &LastIndex );
00751 
00752         // Add the difference between these to the number of colours to be exported. The +1
00753         // in this sum is necessary since the index values include the number of the element
00754         // that they represent. E.g. for a one element ramp, we have 1024 for both the first
00755         // and last items. Thus, without the +1, we would get 0 colours in the index.
00756         NCol += 1 + LastIndex - FirstIndex;
00757     }
00758 
00759     // Write the number of colours.
00760     ExportFile->write ( &NCol, sizeof ( NCol ) );
00761 
00762     // Write as many colours as necessary to get accurate fills. First the start colour.
00763     if(StartPercent != 0)
00764     {
00765         col.ColRef = StartColReference;
00766         col.ColPos = 0;
00767         ExportFile->write(&col, sizeof(col));
00768     }
00769 
00770     col.ColRef = StartColReference;
00771     col.ColPos = (WORD)StartPercent;
00772     ExportFile->write(&col, sizeof(col));
00773 
00774     // If it's a four colour fill, add the middle colour to the mix.
00775     if ( FourColour )
00776     {
00777         col.ColRef  = MidColReference;
00778         col.ColPos  = ( WORD ) ( ( StartPercent + EndPercent ) / 2 );
00779         ExportFile->write ( &col, sizeof ( col ) );
00780     }
00781 
00782     // Process the colour ramp.
00783     if ( pRamp != NULL )
00784     {
00785         ColRampItem *pColour = pRamp->GetFirstCol ();
00786 
00787         // Write in the ramp's colour values.
00788         while ( pColour != NULL )
00789         {
00790             cmxGradFillColour   RampColour;
00791 
00792             // Get the position of the colour in the fill.
00793             RampColour.ColPos   = ( WORD ) ( 100.0f * pColour->GetPosition () );
00794             RampColour.ColRef   = GetColourReference ( &( pColour->GetColour () ) );
00795 
00796             // Write the colour.
00797             ExportFile->write ( &RampColour, sizeof ( RampColour ) );
00798 
00799             // Increment the pointer onto the next item.
00800             pColour = pRamp->GetNextCol ( pColour );
00801         }
00802     }
00803 
00804     // And finally the end colour.
00805     col.ColRef = EndColReference;
00806     col.ColPos = (WORD)EndPercent;
00807     ExportFile->write(&col, sizeof(col));
00808 
00809     if(EndPercent != 100)
00810     {
00811         col.ColPos = 100;
00812         ExportFile->write(&col, sizeof(col));
00813     }
00814 
00815     if(!EndNestedTag())
00816         return FALSE;
00817 
00818     // write the ending bit
00819     if(!WriteMinEndTag())
00820         return FALSE;
00821 
00822     return TRUE;
00823 }
00824 
00825 
00826 /********************************************************************************************
00827 
00828 >   BOOL CMXExportDC::WriteFillSpecBitmap(CMXRenderRegion *pReg, FillGeometryAttribute *pFill, DocCoord *Coords, INT32 NumCoords)
00829 
00830     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00831     Created:    23/07/96
00832     Inputs:     render region
00833     Returns:    success
00834     Purpose:    Writes the bitmap fill specifcation to the DC (also does fractals)
00835 
00836 ********************************************************************************************/
00837 
00838 BOOL CMXExportDC::WriteFillSpecBitmap(CMXRenderRegion *pReg, FillGeometryAttribute *pFill, DocCoord *Coords, INT32 NumCoords)
00839 {
00840     // make up a bitmap fill object -- first find the refer bitmap object necessary
00841     BitmapFillAttribute *pBFillAttr = (BitmapFillAttribute *)pFill;
00842     ERROR3IF(!pBFillAttr->IsKindOf(CC_RUNTIME_CLASS(BitmapFillAttribute)), "not a bitmap fill attr");
00843 
00844     // colours
00845     DocColour *pStartColour = 0;
00846     DocColour *pEndColour = 0;
00847     EFFECTTYPE Effect = EFFECT_RGB;
00848 
00849     // get the colours we should use, and the fill effect
00850     pStartColour = pFill->GetStartColour();
00851     pEndColour = pFill->GetEndColour();
00852     if(pStartColour == 0 || pEndColour == 0
00853         || pStartColour->IsTransparent()
00854         || pEndColour->IsTransparent())
00855     {
00856         pStartColour = 0;
00857         pEndColour = 0;
00858     }
00859     
00860     if(pStartColour != 0)
00861     {
00862         // get the fill effect
00863         Effect = pReg->GetFillEffect();
00864     }
00865 
00866     // get the reference for the bitmap
00867     KernelBitmap *pBitmap = pBFillAttr->BitmapRef.GetBitmap();
00868     WORD BitmapRef = GetBitmapReference(pBitmap, pStartColour, pEndColour, Effect);
00869 
00870     // make a new bitmap fill object
00871     CMXReferBitmapFill *pBFill = new CMXReferBitmapFill(this);
00872     if(pBFill == 0)
00873         return FALSE;
00874     pBFill->Set(BitmapRef);
00875 
00876     // add it to the refer list
00877     ReferList.AddTail(pBFill);
00878 
00879     // get it's reference
00880     WORD BitmapFillProcReference = GetProcedureReference(pBFill);
00881 
00882     // ready to write...
00883     if(!StartNestedTag(cmxTAG_RenderAttr_FillSpec_ColorBM))
00884         return FALSE;
00885     
00886     ExportFile->write(&BitmapFillProcReference, sizeof(BitmapFillProcReference));
00887 
00888     // write tiling
00889     if(!StartNestedTag(cmxTAG_Tiling))
00890         return FALSE;
00891 
00892     // get points from the attribute
00893     DocCoord *Start = pFill->GetStartPoint();
00894     DocCoord *End1 = pFill->GetEndPoint();
00895     DocCoord *End2 = pFill->GetEndPoint2();
00896 
00897     // get a tiling structure
00898     cmxTilingEnd tile;
00899 
00900     // Variables for rendering the texture to the file. I've deferred the scaling of
00901     // the image until it's written. It's slightly ugly doing it this way, but it
00902     // removes a few multipications, and so should get rid of some rounding errors
00903     // along the way.
00904     DocRect cBBox;
00905     double  TileWidth   = Start->Distance ( *End1 );
00906     double  TileHeight  = Start->Distance ( *End2 );
00907 
00908     // Calculate the untransformed Corel bounding box.
00909     CalcCorelBBox(Coords, NumCoords, &cBBox);
00910 
00911     // Graeme (9-5-00) - I've simplified Ben's code a little, and removed the
00912     // repeated bits in both branches of the if statement.
00913     if ( ThirtyTwoBit )
00914     {
00915         cmxTilingBegin32 Tile32;
00916         Tile32.Width    = static_cast<DWORD> ( Round ( TileWidth  * ScaleFactor ) );
00917         Tile32.Height   = static_cast<DWORD> ( Round ( TileHeight * ScaleFactor ) );
00918 
00919         WriteData ( &Tile32, sizeof ( Tile32 ) );
00920     }
00921     else
00922     {
00923         cmxTilingBegin16 Tile16;
00924         Tile16.Width    = static_cast<WORD> ( Round ( TileWidth  * ScaleFactor ) );
00925         Tile16.Height   = static_cast<WORD> ( Round ( TileHeight * ScaleFactor ) );
00926 
00927         WriteData ( &Tile16, sizeof ( Tile16 ) );
00928     }
00929 
00930     // now work out the offsets to the start of the tile
00931     double  dX  = static_cast<double> ( Start->x - cBBox.lo.x );
00932     double  dY  = static_cast<double> ( cBBox.hi.y - Start->y );
00933 
00934     // Graeme (9-5-00) - Round the offset up.
00935     tile.XOffset = ( static_cast<WORD> ( Round ( ( dX * 100.0 ) / TileWidth  ) ) ) % 100;
00936     tile.YOffset = ( static_cast<WORD> ( Round ( ( dY * 100.0 ) / TileHeight ) ) ) % 100;
00937 
00938     tile.InterTileOffset = tile.TilingFlags = 0;
00939 
00940     // write the structure to the file
00941     ExportFile->write(&tile, sizeof(tile));
00942     if(!EndNestedTag() || !WriteMinEndTag())
00943         return FALSE;
00944 
00945     // bounding box of bit to use
00946     DocRect bbox = DocRect(0, 0, cmxBITMAPFILLTILESIZE_X, cmxBITMAPFILLTILESIZE_Y);
00947 
00948     if(!WriteBBox(&bbox, FALSE))
00949         return FALSE;
00950 
00951     if(!EndNestedTag() || !WriteMinEndTag())
00952         return FALSE;
00953 
00954     return TRUE;
00955 }
00956 
00957 
00958 /********************************************************************************************
00959 
00960 >   BOOL CMXExportDC::WritePath ( DocCoord *Coords,
00961                                   PathVerb *Verbs,
00962                                   INT32 NumCoords,
00963                                   BOOL Filled )
00964 
00965     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00966     Created:    01/07/96
00967     Inputs:     render region, coords, verbs and number of coords
00968     Returns:    success
00969     Purpose:    Writes a path instruction -- transformed by matrix
00970 
00971 ********************************************************************************************/
00972 
00973 BOOL CMXExportDC::WritePath ( DocCoord *Coords,
00974                               PathVerb *Verbs,
00975                               INT32 NumCoords,
00976                               BOOL Filled )
00977 {
00978     // if this is one of those nasty 16 bit files, sort out a transform matrix
00979 
00980     // scan the verbs to see if there's a close path in it
00981     // as if there isn't, we need to force no fill on the thingy
00982     BOOL ForceNoFill = TRUE;
00983     for(INT32 p = 0; p < NumCoords; p++)
00984     {
00985         if((Verbs[p] & PT_CLOSEFIGURE) != 0)
00986             ForceNoFill = FALSE;
00987     }
00988     if(!Filled)
00989         ForceNoFill = TRUE;
00990 
00991     // begin the command
00992     if(!StartCommand(cmxINSTR_PolyCurve))
00993         return FALSE;
00994 
00995     // output the rendering attributes
00996     if(!WriteAttributes(pRenderRegion, cmxTAG_PolyCurve_RenderingAttr, Coords, NumCoords, ForceNoFill))
00997         return FALSE;
00998 
00999     // write the point list, transformed of course. Start by tagging it
01000     if(!StartTag(cmxTAG_PolyCurve_PointList))
01001         return FALSE;
01002 
01003     // we have to collect a bounding box as we go through as Corel use a
01004     // naff bbox which is simply the union of all points
01005     DocRect bb;             // which is written as a corel one
01006     DocCoord fc = Coords[0];
01007     pMatrix->transform(&fc);
01008     bb.lo = fc;             // start with sensible coords to begin with
01009     bb.hi = fc;
01010 
01011     // write the point count
01012     WORD Count = (WORD)NumCoords;
01013     ExportFile->write(&Count, sizeof(Count));
01014 
01015     // run through the coords writing and transforming
01016     INT32 l;
01017 TRACEUSER( "Ben", _T("\nPath\n"));
01018     for(l = 0; l < NumCoords; l++)
01019     {
01020         DocCoord Coord = Coords[l];
01021         pMatrix->transform(&Coord);
01022 
01023         // write it...
01024         if(ThirtyTwoBit)
01025         {
01026             cmxPoint32 p = {Coord.x, Coord.y};
01027             ExportFile->write(&p, sizeof(p));
01028         }
01029         else
01030         {
01031 TRACEUSER( "Ben", _T("Coord %d %d\n"), Coord.x, Coord.y);
01032             cmxPoint16 p = {(SWORD)Coord.x, (SWORD)Coord.y};
01033             ExportFile->write(&p, sizeof(p));
01034         }
01035 
01036         // flibble the bounding box with those lovely new coords
01037         if(Coord.x < bb.lo.x) bb.lo.x = Coord.x;
01038         if(Coord.y < bb.lo.y) bb.lo.y = Coord.y;
01039         if(Coord.x > bb.hi.x) bb.hi.x = Coord.x;
01040         if(Coord.y > bb.hi.y) bb.hi.y = Coord.y;
01041     }
01042 
01043     // run through the verbs writing point types
01044     INT32 BezCount = 0;     // for counting Bez
01045     for(l = 0; l < NumCoords; l++)
01046     {
01047         BYTE Type;
01048 
01049         switch(Verbs[l] & (PT_LINETO | PT_MOVETO | PT_BEZIERTO))
01050         {
01051         case PT_MOVETO:
01052             {
01053                 Type = CMXNODETYPE_TYPE_MOVE | CMXNODETYPE_USER;
01054             
01055                 // wibble forwards through the verbs to see if the correspondingness is closed
01056                 for(INT32 lp = l + 1; lp < NumCoords; lp++)
01057                 {
01058                     // OK, is this a move?
01059                     if((Verbs[lp] & (PT_LINETO | PT_MOVETO | PT_BEZIERTO)) == PT_MOVETO)
01060                         break;
01061 
01062                     // is closefigure set?
01063                     if((Verbs[lp] & PT_CLOSEFIGURE) != 0)
01064                     {
01065                         Type |= CMXNODETYPE_CLOSED;
01066                         break;
01067                     }
01068                 }
01069             }
01070             BezCount = 0;
01071             break;
01072 
01073         case PT_LINETO:
01074             Type = CMXNODETYPE_TYPE_LINE | CMXNODETYPE_USER;
01075             BezCount = 0;
01076             break;
01077 
01078         case PT_BEZIERTO:
01079             // in CMX, the control points have type ARC, and the end points
01080             // have type CURVE. This code does the trickery.
01081             if(BezCount == 2)
01082             {
01083                 Type = CMXNODETYPE_TYPE_CURVE | CMXNODETYPE_USER;
01084             }
01085             else
01086             {
01087                 Type = CMXNODETYPE_TYPE_ARC;
01088             }
01089             BezCount++;
01090             if(BezCount > 2)
01091                 BezCount = 0;       // so that only the end points of beziers get user flag
01092             break;
01093 
01094         default:
01095             ERROR3("Unknown node type");
01096             break;
01097         }
01098 
01099         if((Verbs[l] & PT_CLOSEFIGURE) != 0)
01100         {
01101             Type |= CMXNODETYPE_CLOSED;
01102         }
01103 
01104         ExportFile->write(&Type, sizeof(Type));
01105     }
01106 
01107     // end the point list
01108     if(!EndTag())
01109         return FALSE;
01110 
01111     // write bbox we've collected
01112     if(!StartTag(cmxTAG_PolyCurve_BoundingBox)
01113         || !WriteBBox(&bb, FALSE)
01114         || !EndTag())
01115         return FALSE;
01116 
01117     // end the command
01118     if(!WriteMinEndTag()
01119         || !EndCommand())
01120         return FALSE;
01121 
01122     // if necessary, get rid of the horrid transform matrix
01123 
01124     return TRUE;
01125 }
01126 
01127 
01128 /********************************************************************************************
01129 
01130 >   WORD CMXExportDC::GetColourReference(DocColour *pTheLovelyColour)
01131 
01132     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01133     Created:    04/07/96
01134     Inputs:     colour
01135     Returns:    refernce number of a colour
01136     Purpose:    to find a reference number for the colour when writing a CMX file
01137 
01138 ********************************************************************************************/
01139 
01140 WORD CMXExportDC::GetColourReference(DocColour *pTheLovelyColour)
01141 {
01142     // algorithm:
01143     // scan the refer list to see if the colour is already there.
01144     // if it is, return it's index.
01145     // if it isn't add the colour to the refer list, and return the new index.
01146 
01147     // the reference we need -- references count up from 1
01148     INT32 Ref = 0;
01149 
01150     // scan that list!
01151     CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead();
01152     while(pEn != 0)
01153     {
01154         ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list");
01155 
01156         if(pEn->IsInWhichDesc() == cmxDESC_COLOUR)
01157         {
01158             Ref++;
01159 
01160             CMXReferColour *pLC = (CMXReferColour *)pEn;
01161             ERROR3IF(!pLC->IsKindOf(CC_RUNTIME_CLASS(CMXReferColour)), "not a refer colour, when it said it was");
01162             
01163             // is it this colour?
01164             if(pLC->AreYouThisColour(pTheLovelyColour))
01165             {
01166                 // yep. return the reference number
01167                 return Ref;
01168             }
01169         }
01170 
01171         pEn = (CMXReferListItem *)ReferList.GetNext(pEn);
01172     }
01173 
01174     // we haven't got one... make a new one, set it up and add it to the list
01175     CMXReferColour *pNewRefCol = new CMXReferColour(this);
01176     if(pNewRefCol == 0)
01177         return 0;
01178 
01179     pNewRefCol->SetColour(pTheLovelyColour);
01180 
01181     ReferList.AddTail(pNewRefCol);
01182 
01183     // return the next reference number, Ref is the ref of the last one in the list
01184     return (WORD)Ref + 1;
01185 }
01186 
01187 
01188 /********************************************************************************************
01189 
01190 >   WORD CMXExportDC::GetArrowReference(ArrowRec *pArrow)
01191 
01192     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01193     Created:    25/07/96
01194     Inputs:     colour
01195     Returns:    reference number of a colour
01196     Purpose:    to find a reference number for the arrow when writing a CMX file
01197                 will return 0 (ie no arrowhead) if it isn't one
01198 
01199 ********************************************************************************************/
01200 
01201 WORD CMXExportDC::GetArrowReference(ArrowRec *pArrow)
01202 {
01203     // check to see if the arrowrec is in fact an arrowhead
01204     if(pArrow->IsNullArrow())
01205         return 0;       // ie no arrow on here mate
01206 
01207     // the reference we need -- references count up from 1
01208     INT32 Ref = 0;
01209 
01210     // scan that list!
01211     CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead();
01212     while(pEn != 0)
01213     {
01214         ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list");
01215 
01216         if(pEn->IsInWhichDesc() == cmxDESC_ARROW)
01217         {
01218             Ref++;
01219 
01220             CMXReferArrow *pAr = (CMXReferArrow *)pEn;
01221             ERROR3IF(!pAr->IsKindOf(CC_RUNTIME_CLASS(CMXReferArrow)), "not an arrow, when it said it was");
01222             
01223             // is it this colour?
01224             if(pAr->AreYouThisArrow(pArrow))
01225             {
01226                 // yep. return the reference number
01227                 return Ref;
01228             }
01229         }
01230 
01231         pEn = (CMXReferListItem *)ReferList.GetNext(pEn);
01232     }
01233 
01234     // we haven't got one... make a new one, set it up and add it to the list
01235     CMXReferArrow *pNewArrow = new CMXReferArrow(this);
01236     if(pNewArrow == 0)
01237         return 0;
01238 
01239     pNewArrow->Set(pArrow);
01240 
01241     ReferList.AddTail(pNewArrow);
01242 
01243     // return the next reference number, Ref is the ref of the last one in the list
01244     return (WORD)Ref + 1;
01245 }
01246 
01247 
01248 /********************************************************************************************
01249 
01250 >   WORD CMXExportDC::GetBitmapReference(KernelBitmap *pTheLovelyBitmap, DocColour *pStartCol, DocColour *pEndCol, CMXReferBitmap **ppRB = 0)
01251 
01252     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01253     Created:    16/07/96
01254     Inputs:     bitmap
01255     Returns:    refernce number of a bitmap
01256     Purpose:    to find a reference number for the bitmap when writing a CMX file.
01257                 *ppRB is set to a pointer to the CMXReferBitmap object if ppRB != 0
01258 
01259 ********************************************************************************************/
01260 
01261 WORD CMXExportDC::GetBitmapReference(KernelBitmap *pTheLovelyBitmap, DocColour *pStartCol,
01262     DocColour *pEndCol, EFFECTTYPE Effect, CMXReferBitmap **ppRB)
01263 {
01264     // the reference we need -- references count up from 1
01265     INT32 Ref = 0;
01266 
01267     // scan that list!
01268     CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead();
01269     while(pEn != 0)
01270     {
01271         ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list");
01272 
01273         if(pEn->IsInWhichIndex() == cmxINDEX_EMBEDFILE && IS_A(pEn, CMXReferBitmap))
01274         {
01275             Ref++;
01276 
01277             CMXReferBitmap *pBitty = (CMXReferBitmap *)pEn;
01278             
01279             // is it this bitmap?
01280             if(pBitty->AreYouThisBitmap(pTheLovelyBitmap, pStartCol, pEndCol, Effect))
01281             {
01282                 // yep. set bitmap object addr and return the reference number
01283                 if(ppRB != 0)
01284                     (*ppRB) = pBitty;
01285 
01286                 return Ref;
01287             }
01288         }
01289 
01290         pEn = (CMXReferListItem *)ReferList.GetNext(pEn);
01291     }
01292 
01293     // we haven't got one... make a new one, set it up and add it to the list
01294     CMXReferBitmap *pNewRefBit = new CMXReferBitmap(this);
01295     if(pNewRefBit == 0)
01296         return 0;
01297 
01298     pNewRefBit->Set(pTheLovelyBitmap, pStartCol, pEndCol, Effect);
01299 
01300     ReferList.AddTail(pNewRefBit);
01301 
01302     // set bitmap object addr
01303     if(ppRB != 0)
01304         (*ppRB) = pNewRefBit;
01305 
01306     // return the next reference number, Ref is the ref of the last one in the list
01307     return (WORD)Ref + 1;
01308 }
01309 
01310 
01311 /********************************************************************************************
01312 
01313 >   BOOL CMXReferPen::WriteInDesc(CMXExportDC *pDC)
01314 
01315     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01316     Created:    05/07/96
01317     Inputs:     DC
01318     Returns:    success
01319     Purpose:    writes the description record for pens
01320 
01321 ********************************************************************************************/
01322 
01323 BOOL CMXReferPen::WriteInDesc(CMXExportDC *pDC)
01324 {
01325     if(pDC->IsThirtyTwoBit())
01326     {
01327         // write the 32 bit description
01328         if(!pDC->StartTag(cmxTAG_DescrSection_Pen))
01329             return FALSE;
01330 
01331         cmxPen32 pen;
01332 
01333         double scaledwidth = ((double)Width) * CAMCOORD_SCALEFACTOR32;
01334         pen.Width = (DWORD)scaledwidth;
01335         pen.Aspect = 100;       // width is 100% of the height
01336         pen.Angle = 0;
01337         pDC->WriteData(&pen, sizeof(pen));
01338 
01339         // write a matrix (use identity)
01340         if(!pDC->WriteMatrix())
01341             return FALSE;
01342 
01343         // end the tag
01344         if(!pDC->EndTag()
01345             || !pDC->WriteMinEndTag())
01346             return FALSE;
01347     }
01348     else
01349     {
01350         cmxPen16 pen;
01351 
01352         double scaledwidth = ((double)Width) * pDC->GetScaleFactor();
01353         pen.Width = (WORD)scaledwidth;
01354         pen.Aspect = 100;       // width is 100% of the height
01355         pen.Angle = 0;
01356         pDC->WriteData(&pen, sizeof(pen));
01357 
01358         // write a matrix (use identity)
01359         if(!pDC->WriteMatrix())
01360             return FALSE;
01361     }
01362 
01363     return TRUE;
01364 }
01365 
01366 
01367 /********************************************************************************************
01368 
01369 >   BOOL CMXReferArrowheads::WriteInDesc(CMXExportDC *pDC)
01370 
01371     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01372     Created:    05/07/96
01373     Inputs:     DC
01374     Returns:    success
01375     Purpose:    writes the description record for arrowheads
01376 
01377 ********************************************************************************************/
01378 
01379 BOOL CMXReferArrowheads::WriteInDesc(CMXExportDC *pDC)
01380 {
01381     struct {
01382         WORD Start,End;
01383     } en = {Start, End};
01384 
01385     return pDC->WriteData(&en, sizeof(en));
01386 }
01387 
01388 
01389 /********************************************************************************************
01390 
01391 >   BOOL CMXReferLineStyle::WriteInDesc(CMXExportDC *pDC)
01392 
01393     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01394     Created:    05/07/96
01395     Inputs:     DC
01396     Returns:    success
01397     Purpose:    writes the description record for line style
01398 
01399 ********************************************************************************************/
01400 
01401 BOOL CMXReferLineStyle::WriteInDesc(CMXExportDC *pDC)
01402 {
01403     if(!pDC->WriteTag(cmxTAG_DescrSection_LineStyle, &LineStyle, sizeof(LineStyle))
01404         || !pDC->WriteMinEndTag())
01405         return FALSE;
01406 
01407     return TRUE;
01408 }
01409 
01410 
01411 /********************************************************************************************
01412 
01413 >   BOOL CMXReferLineStyle::AreYouThisStyle(cmxLineStyle *pLineStyle)
01414 
01415     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01416     Created:    05/07/96
01417     Inputs:     pointer to a line style description
01418     Returns:    boolean
01419     Purpose:    compares the given line style with the one in the object
01420 
01421 ********************************************************************************************/
01422 
01423 BOOL CMXReferLineStyle::AreYouThisStyle(cmxLineStyle *pLineStyle)
01424 {
01425     // this assume that the structures are packed nicely, and are initialised properly
01426     // failure is not a major problem, just results in larger files
01427     if(memcmp(&LineStyle, pLineStyle, sizeof(cmxLineStyle)) == 0)
01428     {
01429         // they're the same
01430         return TRUE;
01431     }
01432     
01433     // they're not the same
01434     return FALSE;
01435 }
01436 
01437 
01438 /********************************************************************************************
01439 
01440 >   BOOL CMXReferOutline::WriteInDesc(CMXExportDC *pDC)
01441 
01442     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01443     Created:    05/07/96
01444     Inputs:     DC
01445     Returns:    success
01446     Purpose:    writes the description record for the outline
01447 
01448 ********************************************************************************************/
01449 
01450 BOOL CMXReferOutline::WriteInDesc(CMXExportDC *pDC)
01451 {
01452     if(!pDC->WriteTag(cmxTAG_DescrSection_Outline, &Outline, sizeof(Outline))
01453         || !pDC->WriteMinEndTag())
01454         return FALSE;
01455 
01456     return TRUE;
01457 }
01458 
01459 
01460 /********************************************************************************************
01461 
01462 >   BOOL CMXReferOutline::AreYouThisStyle(cmxOutline *pOutline)
01463 
01464     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01465     Created:    05/07/96
01466     Inputs:     pointer to a outline description
01467     Returns:    boolean
01468     Purpose:    compares the given outline with the one in the object
01469 
01470 ********************************************************************************************/
01471 
01472 BOOL CMXReferOutline::AreYouThisOutline(cmxOutline *pOutline)
01473 {
01474     // this assume that the structures are packed nicely, and are initialised properly
01475     // failure is not a major problem, just results in larger files
01476     if(memcmp(&Outline, pOutline, sizeof(cmxOutline)) == 0)
01477     {
01478         // they're the same
01479         return TRUE;
01480     }
01481     
01482     // they're not the same
01483     return FALSE;
01484 }
01485 
01486 
01487 /********************************************************************************************
01488 
01489 >   BOOL CMXExportDC::WriteOutlineSpec(CMXRenderRegion *pReg)
01490 
01491     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01492     Created:    05/07/96
01493     Inputs:     render region
01494     Returns:    sucess
01495     Purpose:    writes the outline specification to the file
01496 
01497 ********************************************************************************************/
01498 
01499 BOOL CMXExportDC::WriteOutlineSpec(CMXRenderRegion *pReg)
01500 {
01501     // algorithm:
01502     // examine the render region and create the structures we want
01503     // this involves scanning the refer list to find the components of the
01504     // outline, and possibly adding new bits to it.
01505     // then, once we've got this structure, we need to scan the list
01506     // to see if it's already there. However, if we needed to create
01507     // anything new in the first phase, we can just skip this.
01508     // but we need to know how many outlines are in there, so
01509     // keep a count in the first bit.
01510 
01511     // find out the line width
01512     MILLIPOINT Width;
01513     // get the attribute
01514     LineWidthAttribute *pLineWidthA
01515             = (LineWidthAttribute *)pReg->GetCurrentAttribute(ATTR_LINEWIDTH);
01516 
01517     // check it out
01518     ERROR2IF(pLineWidthA == 0, FALSE, "No line width attribute");
01519     ERROR3IF(!pLineWidthA->IsKindOf(CC_RUNTIME_CLASS(LineWidthAttribute)), "not a line width attribute");
01520 
01521     Width = pLineWidthA->LineWidth;
01522 
01523     // find the colour
01524     DocColour *pColour;
01525     // get the attribute
01526     StrokeColourAttribute *pColA
01527             = (StrokeColourAttribute *)pReg->GetCurrentAttribute(ATTR_STROKECOLOUR);
01528     // check it out
01529     ERROR2IF(pColA == 0, FALSE, "No stroke colour attribute");
01530     ERROR3IF(!pColA->IsKindOf(CC_RUNTIME_CLASS(StrokeColourAttribute)), "not a stroke colour attribute");
01531 
01532     pColour = pColA->GetStartColour();
01533 
01534     // get the reference for the colour -- check to see if it's transparent
01535     BOOL TransparentLine = FALSE;
01536     WORD ColRef;
01537     if(pColour->IsTransparent())
01538     {
01539         TransparentLine = TRUE;
01540         Width = 0;                  // Graeme (15-2-00) - Remove line if transparent.
01541     }
01542     else
01543         ColRef = GetColourReference(pColour);
01544 
01545     // sort out the line style
01546     cmxLineStyle LineStyle;
01547     LineStyle.Spec = TransparentLine?cmxLINESPEC_NONE:0;
01548     LineStyle.CapAndJoin = 0;
01549 
01550     // find the join type
01551     // get the attribute
01552     JoinTypeAttribute *pJTA
01553             = (JoinTypeAttribute *)pReg->GetCurrentAttribute(ATTR_JOINTYPE);
01554     // check it out
01555     ERROR2IF(pJTA == 0, FALSE, "No join type attribute");
01556     ERROR3IF(!pJTA->IsKindOf(CC_RUNTIME_CLASS(JoinTypeAttribute)), "not a join type attribute");
01557     // set
01558     switch(pJTA->JoinType)
01559     {
01560         case RoundJoin: LineStyle.CapAndJoin |= cmxCAPJOIN_ROUNDJOIN; break;
01561         case BevelledJoin: LineStyle.CapAndJoin |= cmxCAPJOIN_BEVELJOIN; break;
01562         default: break;
01563     }
01564 
01565     // find the end cap
01566     // get the attribute
01567     StartCapAttribute *pSCA
01568             = (StartCapAttribute *)pReg->GetCurrentAttribute(ATTR_STARTCAP);
01569     // check it out
01570     ERROR2IF(pSCA == 0, FALSE, "No start cap attribute");
01571     ERROR3IF(!pSCA->IsKindOf(CC_RUNTIME_CLASS(StartCapAttribute)), "not a start cap attribute");
01572     // set
01573     switch(pSCA->StartCap)
01574     {
01575         case LineCapRound: LineStyle.CapAndJoin |= cmxCAPJOIN_ROUNDCAP; break;
01576         case LineCapSquare: LineStyle.CapAndJoin |= cmxCAPJOIN_SQUARECAP; break;
01577         default: break;
01578     }
01579 
01580     // find the dotdash pattern
01581     DashRec *pDash;
01582     DashPatternAttribute *pDas
01583             = (DashPatternAttribute *)pReg->GetCurrentAttribute(ATTR_DASHPATTERN);
01584     // check it out
01585     ERROR2IF(pDas == 0, FALSE, "No dash pattern attribute");
01586     ERROR3IF(!pDas->IsKindOf(CC_RUNTIME_CLASS(DashPatternAttribute)), "not a dash pattern attribute");
01587     // get it...
01588     pDash = &pDas->DashPattern;
01589 
01590     if(pDash->Elements != 0)
01591         LineStyle.Spec |= cmxLINESPEC_DOTDASH;
01592     else
01593         LineStyle.Spec |= cmxLINESPEC_SOLIDOUTLINE;
01594     
01595     // now we want to aquire some arrowhead references
01596     EndArrowAttribute *pEa
01597             = (EndArrowAttribute *)pReg->GetCurrentAttribute(ATTR_ENDARROW);
01598     // check it out
01599     ERROR2IF(pEa == 0, FALSE, "No arrow attribute");
01600     ERROR3IF(!pEa->IsKindOf(CC_RUNTIME_CLASS(EndArrowAttribute)), "not a arrow attribute");
01601     StartArrowAttribute *pSa
01602             = (StartArrowAttribute *)pReg->GetCurrentAttribute(ATTR_STARTARROW);
01603     // check it out
01604     ERROR2IF(pSa == 0, FALSE, "No arrow attribute");
01605     ERROR3IF(!pSa->IsKindOf(CC_RUNTIME_CLASS(StartArrowAttribute)), "not a arrow attribute");
01606 
01607     // get the arrow references
01608     WORD StartArrow = GetArrowReference(&pSa->StartArrow);
01609     WORD EndArrow = GetArrowReference(&pEa->EndArrow);
01610 
01611     // right then, we need to run through the table to construct the specification
01612     BOOL FoundPen = FALSE;          // whether we found the pen
01613     WORD PenRef = 0;                // reference number for the pen
01614     BOOL FoundLineStyle = FALSE;
01615     WORD LineStyleRef = 0;
01616     BOOL FoundArrowheads = FALSE;
01617     WORD ArrowheadsRef = 0;
01618     BOOL FoundDotDash = FALSE;
01619     WORD DotDashRef = 0;
01620 
01621     WORD LastOutlineRef = 0;        // count up the outlines to find out the ref of the last one
01622 
01623     CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead();
01624     while(pEn != 0)
01625     {
01626         ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list");
01627 
01628         switch(pEn->IsInWhichDesc())
01629         {
01630 
01631         case cmxDESC_PEN:
01632             if(!FoundPen)
01633             {
01634                 PenRef++;
01635 
01636                 CMXReferPen *pPen = (CMXReferPen *)pEn;
01637                 ERROR3IF(!pPen->IsKindOf(CC_RUNTIME_CLASS(CMXReferPen)), "not a refer pen, when it said it was");
01638                 
01639                 // is it this width?
01640                 if(pPen->AreYouThisWidth(Width))
01641                 {
01642                     // yes
01643                     FoundPen = TRUE;
01644                 }
01645             }
01646             break;
01647 
01648         case cmxDESC_LINESTYLE:
01649             if(!FoundLineStyle)
01650             {
01651                 LineStyleRef++;
01652 
01653                 CMXReferLineStyle *pSt = (CMXReferLineStyle *)pEn;
01654                 ERROR3IF(!pSt->IsKindOf(CC_RUNTIME_CLASS(CMXReferLineStyle)), "not a refer LineStyle, when it said it was");
01655                 
01656                 // is it this style?
01657                 if(pSt->AreYouThisStyle(&LineStyle))
01658                 {
01659                     // yes
01660                     FoundLineStyle = TRUE;
01661                 }
01662             }
01663             break;
01664 
01665         case cmxDESC_ARROWHEADS:
01666             if(!FoundArrowheads)
01667             {
01668                 ArrowheadsRef++;
01669 
01670                 CMXReferArrowheads *pAh = (CMXReferArrowheads *)pEn;
01671                 ERROR3IF(!pAh->IsKindOf(CC_RUNTIME_CLASS(CMXReferArrowheads)), "not a arrowheads, when it said it was");
01672                 
01673                 // is it this arrowheads?
01674                 if(pAh->AreYouThisArrowheads(StartArrow, EndArrow))
01675                 {
01676                     // yes
01677                     FoundArrowheads = TRUE;
01678                 }
01679             }
01680             break;
01681 
01682         case cmxDESC_DOTDASH:
01683             if(!FoundDotDash)
01684             {
01685                 DotDashRef++;
01686 
01687                 CMXReferDotDash *pDd = (CMXReferDotDash *)pEn;
01688                 ERROR3IF(!pDd->IsKindOf(CC_RUNTIME_CLASS(CMXReferDotDash)), "not a refer dot dash, when it said it was");
01689                 
01690                 // is it this style?
01691                 if(pDd->AreYouThisDotDash(pDash))
01692                 {
01693                     // yes
01694                     FoundDotDash = TRUE;
01695                 }
01696             }
01697             break;
01698 
01699         case cmxDESC_OUTLINE:
01700             LastOutlineRef++;       // inc the ref for each outline object enountered
01701             break;
01702 
01703         default:
01704             // do nothing
01705             break;
01706         }
01707 
01708         pEn = (CMXReferListItem *)ReferList.GetNext(pEn);
01709     }
01710 
01711     // right then, create some new refer objects if necessary
01712     BOOL NewReferObjectCreated = FALSE;     // whether an refer object was created
01713 
01714     if(!FoundPen)
01715     {
01716         NewReferObjectCreated = TRUE;
01717         // knock up a pen object
01718         CMXReferPen *pPen = new CMXReferPen(this);
01719         if(pPen == NULL)
01720             return FALSE;
01721 
01722         pPen->SetWidth(Width);
01723         PenRef++;               // the reference
01724 
01725         ReferList.AddTail(pPen);
01726     }
01727 
01728     if(!FoundLineStyle)
01729     {
01730         NewReferObjectCreated = TRUE;
01731         // knock up a pen object
01732         CMXReferLineStyle *pLs = new CMXReferLineStyle(this);
01733         if(pLs == NULL)
01734             return FALSE;
01735 
01736         pLs->SetLineStyle(&LineStyle);
01737         LineStyleRef++;             // the reference
01738 
01739         ReferList.AddTail(pLs);
01740     }
01741 
01742     if(!FoundArrowheads)
01743     {
01744         NewReferObjectCreated = TRUE;
01745         // knock up a pen object
01746         CMXReferArrowheads *pAh = new CMXReferArrowheads(this);
01747         if(pAh == NULL)
01748             return FALSE;
01749 
01750         pAh->SetArrowheads(StartArrow, EndArrow);
01751         ArrowheadsRef++;                // the reference
01752 
01753         ReferList.AddTail(pAh);
01754     }
01755 
01756     if(!FoundDotDash)
01757     {
01758         NewReferObjectCreated = TRUE;
01759         // knock up a pen object
01760         CMXReferDotDash *pDd = new CMXReferDotDash(this);
01761         if(pDd == NULL)
01762             return FALSE;
01763 
01764         pDd->Set(pDash);
01765         DotDashRef++;               // the reference
01766 
01767         ReferList.AddTail(pDd);
01768     }
01769 
01770     // make up an outline def
01771     cmxOutline Outline;
01772     memset(&Outline, 0, sizeof(Outline));
01773 
01774     Outline.LineStyle = LineStyleRef;
01775     Outline.Screen = cmxSCREENREFERENCE;
01776     if(TransparentLine)
01777         Outline.Colour = 1;     // any random number will do as long the colour exists
01778     else
01779         Outline.Colour = ColRef;
01780     Outline.Arrowheads = ArrowheadsRef;
01781     Outline.Pen = PenRef;
01782     Outline.DotDash = DotDashRef;
01783 
01784     // run through the table to see if there's a 
01785     BOOL FoundOutline = FALSE;
01786     WORD OutlineRef = 0;
01787     if(NewReferObjectCreated == FALSE) // only bother looking if no new objects have been created
01788     {
01789         CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead();
01790         while(pEn != 0)
01791         {
01792             ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list");
01793 
01794             if(pEn->IsInWhichDesc() == cmxDESC_OUTLINE)
01795             {
01796                 OutlineRef++;
01797 
01798                 CMXReferOutline *pLC = (CMXReferOutline *)pEn;
01799                 ERROR3IF(!pLC->IsKindOf(CC_RUNTIME_CLASS(CMXReferOutline)), "not a refer outline, when it said it was");
01800                 
01801                 // is it this outline?
01802                 if(pLC->AreYouThisOutline(&Outline))
01803                 {
01804                     FoundOutline = TRUE;
01805                     break;
01806                 }
01807             }
01808 
01809             pEn = (CMXReferListItem *)ReferList.GetNext(pEn);
01810         }
01811     }
01812 
01813     // right then, maybe we want to create a new outline object?
01814     if(FoundOutline == FALSE)
01815     {
01816         OutlineRef = LastOutlineRef + 1;
01817 
01818         // make a new object
01819         CMXReferOutline *pOlt = new CMXReferOutline(this);
01820         if(pOlt == NULL)
01821             return FALSE;
01822 
01823         // set it's outline thingy
01824         pOlt->SetOutline(&Outline);
01825 
01826         // and add it to the list
01827         ReferList.AddTail(pOlt);
01828     }
01829 
01830     // finally, write the reference to the file
01831     if(!WriteNestedTag(cmxTAG_RenderAttr_OutlineSpec, &OutlineRef, sizeof(OutlineRef)))
01832         return FALSE;
01833 
01834     // and the end tag
01835     if(!WriteMinEndTag())
01836         return FALSE;
01837 
01838     return TRUE;
01839 }
01840 
01841 
01842 /********************************************************************************************
01843 
01844 >   void CMXExportDC::CalcCorelBBox(DocCoord *Coords, INT32 NumCoords, DocRect &Result)
01845 
01846     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01847     Created:    10/07/96
01848     Inputs:     coords, num coords and output rec
01849     Returns:    -
01850     Purpose:    calculates the corel bounding box of a path. This is just a simple union
01851                 of all point. The result is not transformed by the export transform matrix.
01852 
01853 ********************************************************************************************/
01854 
01855 void CMXExportDC::CalcCorelBBox(DocCoord *Coords, INT32 NumCoords, DocRect *Result)
01856 {
01857     ERROR3IF(Coords == NULL || NumCoords < 1, "dodgy coords");
01858 
01859     // write some sensible starting values
01860     Result->lo = Coords[0];
01861     Result->hi = Coords[0];
01862 
01863     // run through the rest
01864     for(INT32 l = 1; l < NumCoords; l++)
01865     {
01866         if(Result->lo.x > Coords[l].x) Result->lo.x = Coords[l].x;
01867         if(Result->lo.y > Coords[l].y) Result->lo.y = Coords[l].y;
01868         if(Result->hi.x < Coords[l].x) Result->hi.x = Coords[l].x;
01869         if(Result->hi.y < Coords[l].y) Result->hi.y = Coords[l].y;
01870     }
01871 
01872     // sorted
01873 }
01874 
01875 
01876 /********************************************************************************************
01877 
01878 >   BOOL CMXExportDC::WriteAttrCheckLens(CMXRenderRegion *pReg, INT32 Tag, DocCoord *Coords, INT32 NumCoords, BOOL *WasLens)
01879 
01880     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01881     Created:    12/07/96
01882     Inputs:     render region, tag, pointer to flag
01883     Returns:    error flag
01884     Purpose:    checks to see if this object should be outputed as a lens. If so, we need
01885                 to output the attributes for it ourselves (as we can't use the full range
01886                 of possible things) and add things to the list
01887 
01888 ********************************************************************************************/
01889 
01890 WORD CMXExportDC::GetProcedureReference(CMXReferListItem *pProc)
01891 {
01892     ERROR3IF(!pProc->IsAProcedure(), "item is not a procedure");
01893 
01894     // scan the refer list for this item, counting procedures before it
01895     WORD Ref = 0;
01896     CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead();
01897     while(pEn != 0)
01898     {
01899         ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list");
01900 
01901         if(pEn->IsAProcedure())
01902         {
01903             // inc reference number
01904             Ref++;
01905 
01906             // is it this one?
01907             if(pEn == pProc)
01908                 return Ref;
01909         }
01910 
01911         pEn = (CMXReferListItem *)ReferList.GetNext(pEn);
01912     }
01913 
01914     return 1;       // fairly OK default
01915 }
01916 
01917 
01918 /********************************************************************************************
01919 
01920 >   BOOL CMXExportDC::WriteAttrCheckLens(CMXRenderRegion *pReg, INT32 Tag, DocCoord *Coords, INT32 NumCoords, BOOL *WasLens)
01921 
01922     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01923     Created:    12/07/96
01924     Inputs:     render region, tag, pointer to flag
01925     Returns:    error flag
01926     Purpose:    checks to see if this object should be outputed as a lens. If so, we need
01927                 to output the attributes for it ourselves (as we can't use the full range
01928                 of possible things) and add things to the list
01929 
01930 ********************************************************************************************/
01931 
01932 BOOL CMXExportDC::WriteAttrCheckLens(CMXRenderRegion *pReg, INT32 Tag, DocCoord *Coords, INT32 NumCoords, BOOL *WasLens)
01933 {
01934     // set the flag for no lens
01935     *WasLens = FALSE;
01936 
01937     // get the transparency attr
01938     TranspFillAttribute *pTra =
01939         (TranspFillAttribute *)pReg->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY);
01940     // check it out
01941     if(pTra == NULL)
01942     {
01943         TRACEUSER( "Ben", _T("No transparent fill attribute -- assuming it's not transparent\n"));
01944         return TRUE;
01945     }
01946     ERROR3IF(!pTra->IsKindOf(CC_RUNTIME_CLASS(TranspFillAttribute)), "not a transparent fill attribute");
01947 
01948     // right then, let's work out what transparency value we've got here
01949     UINT32 TransparencyValue = 0;
01950     if(pTra->IsAFlatFill())
01951     {
01952         TransparencyValue = *pTra->GetStartTransp();
01953     }
01954     else
01955     {
01956         // average the start and end values
01957         TransparencyValue = (*pTra->GetStartTransp() + *pTra->GetEndTransp()) / 2;
01958     }
01959 
01960     // check to see if we really want to do this thingy
01961     if (TransparencyValue == 0)
01962         return TRUE;            // nothing to do, it's not transparent
01963 
01964     TRACEUSER( "Ben", _T("transparent, has value %d\n"), TransparencyValue);
01965 
01966     // OK, do we want to ignore this lens to stop CorelDRAW from dieing when we import the file
01967     if(WriteAttrCheckIgnoreLens(pReg, Coords, NumCoords))
01968     {
01969         // yes, ignore the damn thing
01970         return TRUE;
01971     }
01972 
01973     // transparency has the range 0-255 in Cam, but 0-1000 in CMX
01974     WORD UniformRate = 1000 - ((TransparencyValue * 1000) / 255);   // the value to export
01975 
01976     // now we need to work out what colour the thingy will be
01977     WORD ColourReference = 1;       // nice default value
01978 
01979     // get the attribute
01980     FillGeometryAttribute *pFillGeometry
01981             = (FillGeometryAttribute *)pReg->GetCurrentAttribute(ATTR_FILLGEOMETRY);
01982 
01983     // check it out
01984     ERROR2IF(pFillGeometry == 0, FALSE, "No fill geometry");
01985     ERROR3IF(!pFillGeometry->IsKindOf(CC_RUNTIME_CLASS(FillGeometryAttribute)), "not one of them there fill geometries");
01986 
01987     // get the start colour of the attribute
01988     DocColour *pColour = pFillGeometry->GetStartColour();
01989 
01990     if(pColour != 0 && !pColour->IsTransparent())
01991     {
01992         // get a reference for this nice colour
01993         ColourReference = GetColourReference(pColour);
01994     }
01995 
01996     // right then, we now need to create one of those lens refer list items
01997     CMXReferLens *pLens = new CMXReferLens(this);
01998     if(pLens == NULL)
01999         return FALSE;
02000 
02001     // get the bounding box
02002     DocRect bb;
02003     CalcCorelBBox(Coords, NumCoords, &bb);
02004 
02005     // set up the lens list item
02006     if(!pLens->Set(this, &bb))
02007         return FALSE;
02008 
02009     // add it to the list
02010     ReferList.AddTail(pLens);
02011 
02012     // right then, we now need to write some attributes to the file
02013     // start the tag
02014     if(Tag != -1)
02015         if(!StartTag(Tag))
02016             return FALSE;
02017 
02018     // write the attribute mask thingy
02019     WriteByte(cmxRENDATTRMASK_FILL | cmxRENDATTRMASK_OUTLINE | cmxRENDATTRMASK_LENS);
02020 
02021     // write the fill specification
02022     if(!StartNestedTag(cmxTAG_RenderAttr_FillSpec)
02023         ||!WriteFillType(cmxFILLID_UNIFORM))
02024         return FALSE;
02025     struct {
02026         WORD FillReference;
02027         WORD ScreenReference;
02028     } filldef = {ColourReference, cmxSCREENREFERENCE};
02029     if(!WriteNestedTag(cmxTAG_RenderAttr_FillSpec_Uniform, &filldef, sizeof(filldef))
02030         || !WriteMinEndTag()
02031         || !EndNestedTag()
02032         || !WriteMinEndTag())
02033         return FALSE;
02034 
02035     // write the outline specification
02036     if(!WriteOutlineSpec(pReg))
02037         return FALSE;
02038 
02039     // and write the lens specification
02040     cmxGlassLensDefn lendef;
02041     lendef.LensType = cmxLENSTYPE_GLASS;
02042 
02043     switch(pTra->GetTranspType())
02044     {
02045         default:            lendef.TintMethod = cmxLENSTINTMETH_AVERAGE;    break;
02046         case TT_StainGlass: lendef.TintMethod = cmxLENSTINTMETH_SUBTRACT;   break;
02047         case TT_Bleach:     lendef.TintMethod = cmxLENSTINTMETH_ADD;        break;
02048     }
02049     lendef.UniformRate = UniformRate;
02050     lendef.ColourReference = ColourReference;
02051     lendef.RangeProcReference = GetProcedureReference(pLens);
02052 
02053     if(!WriteNestedTag(cmxTAG_RenderAttr_LensSpec_Base, &lendef, sizeof(lendef)))
02054         return FALSE;
02055 
02056     if(ThirtyTwoBit)
02057     {
02058         cmxLensFrozView fv;         // no idea what this is
02059         fv.FlagFrozen = 0;
02060         fv.FlagActive = 0;
02061         fv.ViewPointX = 0;
02062         fv.ViewPointY = 0;
02063 
02064         if(!WriteNestedTag(cmxTAG_RenderAttr_LensSpec_FrozViewp, &fv, sizeof(fv))
02065             || !WriteMinEndTag())
02066             return FALSE;
02067     }
02068 
02069     // end the tag
02070     if(Tag != -1)
02071         if(!EndTag())
02072             return FALSE;
02073 
02074     // tell the caller that we did something
02075     *WasLens = TRUE;
02076 
02077     // set the page flag to say we had a lens
02078     SetCMXFlag(cmxSTRUCTFLAGS_HASLENS);
02079 
02080     return TRUE;
02081 }
02082 
02083 
02084 /********************************************************************************************
02085 
02086 >   BOOL CMXExportDC::WriteAttrCheckIgnoreLens(CMXRenderRegion *pReg, DocCoord *Coords, INT32 NumCoords)
02087 
02088     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02089     Created:    22/08/96
02090     Inputs:     region, coords, num coords
02091     Returns:    whether to ignore a lens on this object
02092     Purpose:    checks to see if we should ignore this lens -- it sees if it's going to
02093                 overlap with too many lenses. This is basically as bodge as CorelDRAW will
02094                 just fall over if we export a file with lots of overlapped
02095                 lenses in it.
02096 
02097 ********************************************************************************************/
02098 
02099 BOOL CMXExportDC::WriteAttrCheckIgnoreLens(CMXRenderRegion *pReg, DocCoord *Coords, INT32 NumCoords)
02100 {
02101     // first thing, find the bbox of the object we're about to lens to
02102     DocRect BBox;
02103     CalcCorelBBox(Coords, NumCoords, &BBox);
02104 
02105     // now search the list to see how many existing lenses intersect with it
02106     INT32 LensesBehindThisOne = 0;
02107     CMXLensBBox *pEn = (CMXLensBBox *)LensBBoxes.GetHead();
02108     while(pEn != 0)
02109     {
02110         // check for intersection
02111         if(pEn->DoesIntersect(&BBox))
02112             LensesBehindThisOne++;
02113 
02114         // next, please
02115         pEn = (CMXLensBBox *)LensBBoxes.GetNext(pEn);
02116     }
02117 
02118     // make up a new object to add to the nice list thingy
02119     CMXLensBBox *pNewLensBBox = new CMXLensBBox(&BBox);
02120     if(pNewLensBBox != NULL)
02121         LensBBoxes.AddTail(pNewLensBBox);
02122 
02123     // do we want to ignore this?
02124     if(LensesBehindThisOne > CMX_MAX_OVERLAP_LENSES)
02125     {
02126         TRACEUSER( "Ben", _T("found transparency to ignore, %d lenses behind\n"), LensesBehindThisOne);
02127         // maybe we could ask the user if it wanted to ignore the overlapped things
02128         if(!AreIgnoreingOverlappedLenses && !HaveAskedUserAboutLenses)
02129         {
02130             HaveAskedUserAboutLenses = TRUE;
02131 
02132             INT32 Result = InformWarning(_R(IDW_CMXOVERLAPPEDLENS), _R(IDB_CMXDOLENSES), _R(IDB_CMXIGNORELENSES), 0, 0, 2, 1);
02133 
02134             switch(Result)
02135             {
02136             case 1: //_R(IDB_CMXDOLENSES):
02137                 AreIgnoreingOverlappedLenses = FALSE;
02138                 break;
02139 
02140             case 2: //_R(IDB_CMXIGNORELENSES):
02141             default:
02142                 AreIgnoreingOverlappedLenses = TRUE;
02143                 break;
02144             }
02145         }
02146 
02147         // ignore it?
02148         if(AreIgnoreingOverlappedLenses)
02149         {
02150             // OK, we've got to ignore this -- mark the fact
02151             OverlappedLensesHaveBeenIgnored = TRUE;
02152 
02153             return TRUE;        // ignore it
02154         }
02155     }
02156 
02157     return FALSE;       // don't ignore this one
02158 }
02159 
02160 
02161 /********************************************************************************************
02162 
02163 >   BOOL CMXReferLens::Set(CMXExportDC *pDC, DocRect *tBBox)
02164 
02165     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02166     Created:    12/07/96
02167     Inputs:     export DC, bounding box of lens object
02168     Returns:    error flag
02169     Purpose:    sets up the data this thingy needs
02170 
02171 ********************************************************************************************/
02172 
02173 BOOL CMXReferLens::Set(CMXExportDC *pDC, DocRect *tBBox)
02174 {
02175     // copy in the bounding box
02176     BBox = *tBBox;
02177 
02178     // get the position of the command
02179     CommandFilePosition = pDC->GetCurrentInstrFilePosition();
02180 
02181     // get the layer number
02182     LayerNumber = pDC->GetLayerNumber();
02183     
02184     return TRUE;
02185 }
02186 
02187 
02188 /********************************************************************************************
02189 
02190 >   BOOL CMXReferLens::WriteSection(CMXExportDC *pDC)
02191 
02192     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02193     Created:    12/07/96
02194     Inputs:     export DC
02195     Returns:    error flag
02196     Purpose:    writes the lens descrition section
02197 
02198 ********************************************************************************************/
02199 
02200 BOOL CMXReferLens::WriteSection(CMXExportDC *pDC)
02201 {
02202     // note the position of this thingy for future reference
02203     LensDescFilePosition = pDC->GetFilePosition();
02204 
02205     // start the section
02206     if(!pDC->StartSection(CMXExportDC::CMXSECTION_LENS))
02207         return FALSE;
02208 
02209     // write the header
02210     cmxLensDescriptionSection len;
02211     len.ParentType = cmxREFLISTEN_TYPE_LAYER;
02212     len.Page = 1;
02213     len.ParentReference = LayerNumber;
02214     len.StartAddress = pDC->GetFirstInstrFilePosition();
02215     len.EndAddress = CommandFilePosition;
02216     pDC->WriteData(&len, sizeof(len));
02217 
02218     // write the bbox
02219     Matrix *pMat = pDC->GetTransMatrix();
02220     DocRect b = BBox;
02221     pMat->TransformBounds(&b);
02222     if(!pDC->WriteBBox(&b))
02223         return FALSE;
02224 
02225     // end the section
02226     if(!pDC->EndSection())
02227         return FALSE;
02228 
02229     return TRUE;
02230 }
02231 
02232 
02233 
02234 /********************************************************************************************
02235 
02236 >   BOOL CMXReferLens::WriteInReferenceList(CMXExportDC *pDC)
02237 
02238     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02239     Created:    12/07/96
02240     Inputs:     export dc
02241     Returns:    success
02242     Purpose:    writes the relevant entry in the reference list of the file
02243     SeeAlso:    
02244 
02245 ********************************************************************************************/
02246 
02247 BOOL CMXReferLens::WriteInReferenceList(CMXExportDC *pDC)
02248 {
02249     ERROR2IF(pDC == 0, FALSE, "no DC");
02250 
02251     // write the entry
02252     cmxRefListEntryRefOffset en;
02253     memset(&en, '\0', sizeof(en));
02254 
02255     en.Association = cmxREFLISTEN_DESC_LENS;
02256     en.Type = cmxREFLISTEN_TYPE_INSTRUCTION;
02257     en.Offset = CommandFilePosition;
02258 
02259     pDC->WriteData(&en, sizeof(en));
02260 
02261     return TRUE;
02262 }
02263 
02264 
02265 /********************************************************************************************
02266 
02267 >   BOOL CMXReferLens::WriteInIndex(CMXExportDC *pDC)
02268 
02269     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02270     Created:    12/07/96
02271     Inputs:     export dc
02272     Returns:    success
02273     Purpose:    writes the relevant entry in the procedure index of the file
02274     SeeAlso:    
02275 
02276 ********************************************************************************************/
02277 
02278 BOOL CMXReferLens::WriteInIndex(CMXExportDC *pDC)
02279 {
02280     // write the index entry
02281     cmxProcIndexEntry en;
02282     pDC->WriteSizeInFile(sizeof(en));
02283     en.RefList = -1;
02284     en.Procedure = LensDescFilePosition;
02285 
02286     return pDC->WriteData(&en, sizeof(en));
02287 }
02288 
02289 
02290 /********************************************************************************************
02291 
02292 >   BOOL CMXReferBitmapFill::WriteInIndex(CMXExportDC *pDC)
02293 
02294     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02295     Created:    12/07/96
02296     Inputs:     export dc
02297     Returns:    success
02298     Purpose:    writes the relevant entry in the procedure index of the file
02299     SeeAlso:    
02300 
02301 ********************************************************************************************/
02302 
02303 BOOL CMXReferBitmapFill::WriteInIndex(CMXExportDC *pDC)
02304 {
02305     // write the index entry
02306     cmxProcIndexEntry en;
02307     pDC->WriteSizeInFile(sizeof(en));
02308     en.RefList = -1;
02309     en.Procedure = ProcedureFilePosition;
02310 
02311     return pDC->WriteData(&en, sizeof(en));
02312 }
02313 
02314 
02315 /********************************************************************************************
02316 
02317 >   BOOL CMXReferBitmap::WriteInIndex(CMXExportDC *pDC)
02318 
02319     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02320     Created:    15/07/96
02321     Inputs:     export dc
02322     Returns:    success
02323     Purpose:    writes the relevant entry in the procedure index of the file
02324     SeeAlso:    
02325 
02326 ********************************************************************************************/
02327 
02328 BOOL CMXReferBitmap::WriteInIndex(CMXExportDC *pDC)
02329 {
02330     cmxEmbedFileIndexEntry en;
02331     pDC->WriteSizeInFile(sizeof(en));
02332     en.Offset = BitmapFileOffset;
02333     en.Type = cmxEMBEDFILETYPE_RIMAGE;
02334 
02335     return pDC->WriteData(&en, sizeof(en));
02336 }
02337 
02338 
02339 /********************************************************************************************
02340 
02341 >   BOOL CMXReferBitmap::WriteSection(CMXExportDC *pDC)
02342 
02343     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02344     Created:    15/07/96
02345     Inputs:     export dc
02346     Returns:    success
02347     Purpose:    writes the relevant entry in the procedure index of the file
02348     SeeAlso:    
02349 
02350 ********************************************************************************************/
02351 
02352 BOOL CMXReferBitmap::WriteSection(CMXExportDC *pDC)
02353 {
02354     // get the winoil bitmap associated with this thingy
02355     // this is non kernelally stuff, but noone else cares when they do it
02356     KernelBitmap *pBitmap = Ref.GetBitmap();
02357     ERROR2IF(pBitmap == NULL, FALSE, "no bitmap in ref");
02358     OILBitmap *bit = pBitmap->ActualBitmap;
02359     ERROR2IF(bit == NULL, FALSE, "kernel bitmap didn't have a oil bitmap");
02360 
02361     // note the position of the thingy
02362     BitmapFileOffset = pDC->GetFilePosition();
02363 
02364     // contone?
02365     if(Contone)
02366     {
02367         // grab a view for us to use in the following call
02368         View *pView = NULL;
02369         if (pDC->GetRenderRegion()!=NULL)
02370             pView=pDC->GetRenderRegion()->GetRenderView();
02371 
02372         // build the contone bitmap
02373         if (!bit->BuildContonePalette(StartColour, EndColour, Effect, pView))
02374             return FALSE;
02375 
02376         // tell the render region we're exporting a contone bitmap
02377         pDC->GetRenderRegion()->SetAreExportingContoneBitmap(TRUE);
02378     }
02379     else
02380     {
02381         // we're not doing a contoned bitmap
02382         pDC->GetRenderRegion()->SetAreExportingContoneBitmap(FALSE);
02383     }
02384 
02385     // export the bitmap
02386     if(!bit->ExportBitmap(pDC->GetRenderRegion()))
02387         return FALSE;
02388 
02389     if(Contone)
02390     {
02391         // Clean up contone palette
02392         bit->DestroyContonePalette();
02393     }
02394 
02395     return TRUE;
02396 }
02397 
02398 
02399 /********************************************************************************************
02400 
02401 >   BOOL CMXReferBitmapFill::WriteSection(CMXExportDC *pDC)
02402 
02403     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02404     Created:    15/07/96
02405     Inputs:     export dc
02406     Returns:    success
02407     Purpose:    writes the relevant entry in the procedure index of the file
02408     SeeAlso:    
02409 
02410 ********************************************************************************************/
02411 
02412 BOOL CMXReferBitmapFill::WriteSection(CMXExportDC *pDC)
02413 {
02414     // get the file position for our records
02415     ProcedureFilePosition = pDC->GetFilePosition();
02416 
02417     // first step -- start the procedure section
02418     if(!pDC->StartSection(CMXExportDC::CMXSECTION_PROCBITFILL))
02419         return FALSE;
02420 
02421     // bounding box
02422     DocRect bbox = DocRect(0, 0, cmxBITMAPFILLTILESIZE_X, cmxBITMAPFILLTILESIZE_Y);
02423 
02424     // put in the start the procedure
02425     if(!pDC->StartPage(&bbox, TRUE))
02426         return FALSE;
02427 
02428     // write the bitmap object
02429     DocCoord Paral[4] =             // bouning parallelogram of the bitmap
02430         {   DocCoord(0, cmxBITMAPFILLTILESIZE_Y),
02431             DocCoord(cmxBITMAPFILLTILESIZE_X, cmxBITMAPFILLTILESIZE_Y),
02432             DocCoord(cmxBITMAPFILLTILESIZE_X, 0),
02433             DocCoord(0, 0)
02434         };
02435 
02436     if ( !pDC->WriteBitmap ( 0, Paral, CMXExportDC::CMXBITMAPCOLOURSOURCE_NONE,
02437                              FALSE, BitmapReference ) )
02438         return FALSE;
02439 
02440     // end the page
02441     if(!pDC->EndPage())
02442         return FALSE;
02443 
02444     // end the section
02445     if(!pDC->EndSection())
02446         return FALSE;
02447 
02448     return TRUE;
02449 }
02450 
02451 
02452 /********************************************************************************************
02453 
02454 >   BOOL CMXExportDC::WriteBitmap ( KernelBitmap            *pBitmap,
02455                                     DocCoord                *pParallelogram,
02456                                     CMXBitmapColourSource   ColSource,
02457                                     BOOL                    TransformParallelogram,
02458                                     WORD                    BitmapReference )
02459 
02460     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02461     Created:    15/07/96
02462     Inputs:     render region, bitmap, parllelogram for the bitmap
02463     Returns:    success
02464     Purpose:    writes a bitmap object to the file
02465     SeeAlso:    
02466 
02467 ********************************************************************************************/
02468 
02469 BOOL CMXExportDC::WriteBitmap ( KernelBitmap            *pBitmap,
02470                                 DocCoord                *pParallelogram,
02471                                 CMXBitmapColourSource   ColSource,
02472                                 BOOL                    TransformParallelogram,
02473                                 WORD                    BitmapReference )
02474 {
02475     // sort out some colours for contoning the bitmap
02476     DocColour *pStartColour = 0;
02477     DocColour *pEndColour = 0;
02478     EFFECTTYPE Effect = EFFECT_RGB;
02479 
02480     // we have three possible methods for getting some colours...
02481     switch(ColSource)
02482     {
02483     case CMXBITMAPCOLOURSOURCE_FILLGEOMETRY:
02484         ERROR2(FALSE, "fill geometry bitmap colour source not implemented");
02485         break;
02486 
02487     case CMXBITMAPCOLOURSOURCE_LINEANDFILL:
02488         {
02489         // right then, we get the start colour from the line effect
02490         // get the attribute
02491         StrokeColourAttribute *pColA
02492                 = (StrokeColourAttribute *)pRenderRegion->GetCurrentAttribute(ATTR_STROKECOLOUR);
02493         // check it out
02494         ERROR2IF(pColA == 0, FALSE, "No stroke colour attribute");
02495         ERROR3IF(!pColA->IsKindOf(CC_RUNTIME_CLASS(StrokeColourAttribute)), "not a stroke colour attribute");
02496         pStartColour = pColA->GetStartColour();
02497         // check to see if we need to do contoning
02498         if(pStartColour != 0 && pStartColour->IsTransparent())
02499             pStartColour = 0;
02500 
02501         // get the end colour from a fill attribute
02502         if(pStartColour != 0)
02503         {
02504             // get the attribute
02505             FillGeometryAttribute *pFillGeometry
02506                     = (FillGeometryAttribute *)pRenderRegion->GetCurrentAttribute(ATTR_FILLGEOMETRY);
02507             // check it out
02508             ERROR2IF(pFillGeometry == 0, FALSE, "No fill geometry");
02509             ERROR3IF(!pFillGeometry->IsKindOf(CC_RUNTIME_CLASS(FillGeometryAttribute)), "not one of them there fill geometries");
02510 
02511             // get the start colour of the fill attribute
02512             pEndColour = pFillGeometry->GetStartColour();
02513 
02514             if(pEndColour == NULL || pEndColour->IsTransparent())
02515             {
02516                 // no end colour -- can't be contoned then
02517                 pStartColour = 0;
02518                 pEndColour = 0;
02519             }
02520             else
02521             {
02522                 // get the fill effect
02523                 Effect = pRenderRegion->GetFillEffect();
02524             }
02525         }
02526         }
02527         break;
02528 
02529     default:
02530     case CMXBITMAPCOLOURSOURCE_NONE:
02531         break;      // do nothing
02532     }
02533 
02534     // get a reference number for the bitmap
02535     WORD BitmapRef = 0;
02536     if(pBitmap == 0)
02537     {
02538         BitmapRef = BitmapReference;
02539     }
02540     else
02541     {
02542         BitmapRef = GetBitmapReference(pBitmap, pStartColour, pEndColour, Effect);
02543     }
02544     if(BitmapRef == 0)
02545         return TRUE;            // if it isn't able to be got, sod it.
02546 
02547     // make a new transformed parallelogram thingy
02548     DocCoord Para[4];
02549     ERROR2IF(pMatrix == NULL, FALSE, "no matrix");
02550     for(INT32 z = 0; z < (sizeof(Para) / sizeof(DocCoord)); z++)
02551     {
02552         Para[z] = pParallelogram[z];
02553         if(TransformParallelogram)
02554             pMatrix->transform(&(Para[z]));
02555     }
02556 
02557     // begin the command
02558     if(!StartCommand(cmxINSTR_DrawImage))
02559         return FALSE;
02560 
02561     // output the rendering attributes
02562     if(!WriteBlankAttributes(cmxTAG_DrawImage_RenderingAttr))
02563         return FALSE;
02564 
02565     // write the image data
02566     if(!StartTag(cmxTAG_DrawImage_DrawImageSpecification))
02567         return FALSE;
02568 
02569     // image extent and cropping rectangle, in pixels
02570     DocRect ImEx;
02571     if(ThirtyTwoBit)
02572     {
02573         ImEx.lo.x = ImEx.lo.y = 0;
02574         ImEx.hi.x = 2048;
02575         ImEx.hi.y = 2048;
02576     }
02577     else
02578     {
02579         ImEx.lo.x = 0;
02580         ImEx.lo.y = -2048;
02581         ImEx.hi.x = 2048;
02582         ImEx.hi.y = 0;
02583     }
02584     if(!WriteBBox(&ImEx, FALSE) ||
02585         !WriteBBox(&ImEx, FALSE))
02586         return FALSE;
02587 
02588     // construct a transformation matrix -- no point in going through the write matrix fn
02589     double magX = 2048.0;
02590     double magY = 2048.0;
02591     cmxMatrix Matrix = {cmxMATRIXTYPE_GENERAL,
02592         (double)(Para[2].x - Para[3].x) / magX,
02593         (double)(Para[2].y - Para[3].y) / magY,
02594         (double)(Para[0].x - Para[3].x) / magX,
02595         (double)(Para[0].y - Para[3].y) / magY,
02596         Para[3].x,
02597         Para[3].y};
02598 
02599     if(!ThirtyTwoBit)
02600     {
02601         // add correction for bitmapnesses in 16 bit CMX files
02602         Matrix.f += Matrix.d * 2048;
02603     }
02604 
02605     // save out the matrix
02606     ExportFile->write(&Matrix, sizeof(Matrix));
02607 
02608     // other bits and pieces
02609     cmxDrawImageEndBits eb;
02610     eb.ImageType = cmxDRAWIMAGE_IMAGETYPE_COLOUR;
02611     eb.FileRef1 = BitmapRef;
02612     eb.FileRef2 = 0;            // nothing associated with this
02613     if(!WriteData(&eb, sizeof(eb)))
02614         return FALSE;
02615 
02616     // end the specification thingy
02617     if(!EndTag())
02618         return FALSE;
02619 
02620     // end the command
02621     if(!WriteMinEndTag()
02622         || !EndCommand())
02623         return FALSE;
02624 
02625     return TRUE;
02626 }

Generated on Sat Nov 10 03:44:43 2007 for Camelot by  doxygen 1.4.4