doccolor.cpp

Go to the documentation of this file.
00001 // $Id: doccolor.cpp 1605 2006-07-29 19:26:03Z 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 // doccolor.cpp - the DocColour class
00099 
00100 /*
00101 */
00102 
00103 
00104 #include "camtypes.h"
00105 
00106 //#include "colcontx.h"
00107 #include "colormgr.h"
00108 #include "colourix.h"
00109 #include "colplate.h"
00110 //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 
00113 
00114 CC_IMPLEMENT_MEMDUMP(DocColour, CC_CLASS_MEMDUMP)
00115 
00116 
00117 #ifdef _DEBUG
00118 // --- Comment out the line below to disable IndexedColour usage tracing
00119 //#define TRACECOLOURIX 1
00120 // ---
00121 #endif
00122 
00123 // Declare smart memory handling in Debug builds
00124 #define new CAM_DEBUG_NEW
00125 
00126 /*  DEFAULTCONTEXT(ColourModel)
00127  *  Macro to find a pointer to the global default colour context for a given
00128  *  Colour Model.
00129  *      eg: DEFAULTCONTEXT(ColModel)->PackColour(...);
00130  */
00131 #define DEFAULTCONTEXT(colmodel) (ColourContext::GetGlobalDefault((ColourModel)colmodel))
00132 
00133 /********************************************************************************************
00134 
00135 >   void DocColour::InitialiseInfoField(void)
00136 
00137     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00138     Created:    30/03/94
00139     Inputs:     -
00140     Outputs:    -
00141     Returns:    -
00142     Purpose:    Private shared code for construction of DocColour objects
00143                 Initialises the 'Info' structure to default values
00144     Scope:      private
00145     Errors:     -
00146     SeeAlso:    -
00147 
00148 ********************************************************************************************/
00149 
00150 void DocColour::InitialiseInfoField(ColourModel ColModel)
00151 {
00152     ENSURE((INT32) ColModel < MAX_COLOURMODELS,
00153             "Attempt to use illegal colour model!");
00154 
00155     Info.Reserved           = 0;        // Reserved - set to zero for safety
00156 
00157     Info.OCContextHandle    = 0;
00158     Info.SourceColourModel  = ColModel;
00159     Info.CacheColourModel   = COLOURMODEL_NOTCACHED;
00160 
00161     Info.IsSeparable        = TRUE;
00162 
00163     Info.ForceRounding      = FALSE;
00164 
00165     Info.NoColour           = FALSE;
00166 }
00167 
00168 /********************************************************************************************
00169 
00170 >   DocColour::DocColour()
00171 
00172     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00173     Created:    30/03/94
00174     Inputs:     -
00175     Outputs:    -
00176     Returns:    -
00177     Purpose:    Constructor for a DocColour
00178                 Initialises the colour to an RGBT value representing 'no colour'.
00179                 (i.e. The same as DocColour(COLOUR_TRANS))
00180     Errors:     -
00181     SeeAlso:    -
00182 
00183 ********************************************************************************************/
00184 
00185 DocColour::DocColour()
00186 {
00187     ZapSourceColour();
00188     InitialiseInfoField(COLOURMODEL_RGBT);
00189 
00190     SourceColour.RGBT.Red           = 0;    // Black & 100% Transparent
00191     SourceColour.RGBT.Green         = 0;
00192     SourceColour.RGBT.Blue          = 0;
00193     SourceColour.RGBT.Transparent   = 255;
00194 
00195     Info.NoColour = TRUE;                   // And also 'no colour' transparent
00196 }
00197 
00198 
00199 
00200 /********************************************************************************************
00201 
00202 >   DocColour::~DocColour()
00203 
00204     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00205     Created:    30/03/94
00206     Inputs:     -
00207     Outputs:    -
00208     Returns:    -
00209     Purpose:    Destructor for a DocColour
00210     Errors:     -
00211     SeeAlso:    -
00212 
00213 ********************************************************************************************/
00214 
00215 DocColour::~DocColour()
00216 {
00217     // If we are a reference to an indexed colour, tell that colour that we are
00218     // no longer referencing it
00219     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
00220         SourceColour.Indexed.Colour->DecrementUsage();
00221 }
00222 
00223 
00224 
00225 
00226 
00227 
00228 
00229 /********************************************************************************************
00230 
00231 >   DocColour::DocColour(StockColour Col)
00232 
00233     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00234     Created:    06/04/94
00235     Inputs:     Col - Identifies the stock colour to create
00236     Outputs:    -
00237     Returns:    -
00238     Purpose:    Constructor for a DocColour
00239                 Initialises it to the given predefined (stock) colours, as defined
00240                 in stockcol.h (cf keyword StockColour)
00241 
00242     Notes:      ALL StockColours are non-separable colours!
00243                 i.e. they should only be applied to user-interface rendering
00244 
00245     Errors:     -
00246     SeeAlso:    StockColour
00247 
00248 ********************************************************************************************/
00249 
00250 DocColour::DocColour(StockColour Col)
00251 {
00252     ZapSourceColour();
00253     PColourValue Red = 0, Green = 0, Blue = 0, Transparent = 0;
00254 
00255     InitialiseInfoField(COLOURMODEL_RGBT);
00256 
00257     switch (Col)
00258     {
00259         case COLOUR_TRANS:
00260             Red = Green = Blue = Transparent = 255;
00261             Info.NoColour = TRUE;
00262             break;
00263 
00264         case COLOUR_BLACK:
00265         case COLOUR_UNSELECTEDBLOB:
00266         case COLOUR_FILLDEFAULT:
00267         case COLOUR_LINEDEFAULT:
00268         case COLOUR_XORDRAG:
00269             break;
00270 
00271         case COLOUR_DKGREY:
00272             Red = Green = Blue =  64;
00273             break;
00274 
00275         case COLOUR_MIDGREY:
00276             Red = Green = Blue = 128;
00277             break;
00278 
00279         case COLOUR_XOREDIT:
00280             Red = 64;
00281             Green = 64;
00282             Blue = 230;
00283             break;
00284 
00285         case COLOUR_LTGREY:
00286         case COLOUR_BEZIERLINE:
00287             Red = Green = Blue = 192;
00288             break;
00289 
00290         case COLOUR_WHITE:
00291             Red = Green = Blue = 255;
00292             break;
00293 
00294         case COLOUR_RED:
00295         case COLOUR_XORSELECT:
00296         case COLOUR_TOOLBLOB:
00297         case COLOUR_SELECTEDBLOB:
00298         case COLOUR_BEZIERBLOB:
00299             Red     = 255;
00300             break;
00301 
00302         case COLOUR_GREEN:
00303             Green   = 255;
00304             break;
00305 
00306         case COLOUR_BLUE:
00307         case COLOUR_XORNEW:
00308         case COLOUR_GRID:
00309             Blue    = 255;
00310             break;
00311 
00312         case COLOUR_CYAN:
00313             Green  = Blue = 255;
00314             break;
00315 
00316         case COLOUR_MAGENTA:
00317             Red = Blue = 255;
00318             break;
00319 
00320         case COLOUR_YELLOW:
00321             Red = Green = 255;
00322             break;
00323     }
00324 
00325 
00326     SourceColour.RGBT.Red           = Red;
00327     SourceColour.RGBT.Green         = Green;
00328     SourceColour.RGBT.Blue          = Blue;
00329     SourceColour.RGBT.Transparent   = Transparent;
00330 
00331     Info.IsSeparable = FALSE;
00332 }
00333 
00334 
00335 
00336 
00337 /********************************************************************************************
00338 
00339 >   DocColour::DocColour(ColourValue Red, ColourValue Green, ColourValue Blue)
00340 
00341     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00342     Created:    30/03/94
00343     Inputs:     Red; Green; Blue - The RGB definition of the colour
00344     Outputs:    -
00345     Returns:    -
00346     Purpose:    Constructor for a DocColour
00347                 Initialises it to the given RGBT value.
00348                 Values are ColourValues (FIXED24s) in the range 0.0 to 1.0
00349 
00350     Notes:      DocColours no longer support transparency/transtype.
00351 
00352     Errors:     -
00353     SeeAlso:    -
00354 
00355 ********************************************************************************************/
00356 
00357 DocColour::DocColour(ColourValue Red, ColourValue Green, ColourValue Blue)
00358 {
00359     ZapSourceColour();
00360     ColourRGBT temp;
00361 
00362     InitialiseInfoField( COLOURMODEL_RGBT );
00363 
00364     temp.Red            = Red;          // Copy data into 128-bit struct, then pack
00365     temp.Green          = Green;        // it into our 32-bit store.
00366     temp.Blue           = Blue;
00367     temp.Transparent    = 0;
00368 
00369     DEFAULTCONTEXT(COLOURMODEL_RGBT)->PackColour( (ColourGeneric *)&temp, &SourceColour );
00370 }
00371 
00372 
00373 
00374 /********************************************************************************************
00375 
00376 >   DocColour::DocColour(ColourModel ColModel, ColourGeneric *Col)
00377 
00378     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00379     Created:    30/03/94
00380     Inputs:     ColModel - Colour model in which Col is defined
00381                 Col - definition of the colour in model ColModel
00382     Outputs:    -
00383     Returns:    -
00384     Purpose:    Constructor for a DocColour
00385                 Initialises it to the given value
00386 
00387     Notes:      Note the existence of the macros:
00388                     DOCCOLOUR_RGBT(Colour_RGBT *col)
00389                     DOCCOLOUR_CMYK(Colour_CMYK *col)
00390                     DOCCOLOUR_HSVT(Colour_HSVT *col)
00391                     DOCCOLOUR_CIET(COLOUR_CIET *col)
00392                 which can be used to create DocColours from ColourRGBT etc structs
00393                 e.g.
00394                     ColourRGBT AnRGBTColourDefn;
00395                     DocColour  MyRGBT = DOCCOLOUR_RGBT(&AnRGBTColourDefn);
00396                 These macros are defined in doccolor.h
00397 
00398     Errors:     -
00399     SeeAlso:    -
00400 
00401 ********************************************************************************************/
00402 
00403 DocColour::DocColour(ColourModel ColModel, ColourGeneric *Col)
00404 {
00405     ZapSourceColour();
00406     InitialiseInfoField(ColModel);
00407     DEFAULTCONTEXT(ColModel)->PackColour(Col, &SourceColour);
00408 }
00409 
00410 
00411 
00412 /********************************************************************************************
00413 
00414 >   DocColour::DocColour(const DocColour &other);
00415 
00416     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00417     Created:    14/04/94
00418     Inputs:     Other - colour to copy
00419     Outputs:    -
00420     Returns:    
00421     Purpose:    DocColour copy constructor
00422     Notes:      If copying a reference to an indexed colour, the indexed colours
00423                 usage count will be incremented.
00424                 If this is already a reference to an indexed colour, that indexed
00425                 colours usage count will be decremented.
00426     Errors:     -
00427 
00428 ********************************************************************************************/
00429 
00430 DocColour::DocColour(const DocColour &Other)
00431 {
00432     ENSURE(Other.Info.SourceColourModel < MAX_COLOURMODELS,
00433             "Attempt to use illegal colour model!");
00434 
00435     Info = Other.Info;
00436     CachedColour = Other.CachedColour;
00437     SourceColour = Other.SourceColour;
00438 
00439     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
00440     {
00441         ENSURE(SourceColour.Indexed.Colour != NULL,
00442                 "Corrupted DocColour (NULL IndexedColour ref) detected");
00443 
00444         SourceColour.Indexed.Colour->IncrementUsage();
00445         ENSURE(Info.CacheColourModel == 0, "RefToIndexedColour DocColour has a cache!!");
00446 
00447 #ifdef TRACECOLOURIX
00448 TRACE( _T(">> Construct DocColour(DocColour => ColourIx %x) @ %x\n"), (INT32)SourceColour.Indexed.Colour, (INT32)this);
00449 #endif
00450     }
00451 }
00452 
00453 
00454 
00455 /********************************************************************************************
00456 
00457 >   DocColour::DocColour(IndexedColour *Col)
00458     
00459     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00460     Created:    30/03/94
00461     Purpose:    {Copy} Constructor for a DocColour
00462     Notes:      THIS FUNCTION DOES NOT EXIST!!
00463                 DocColour::MakeRefToIndexedColour() should be used if you wish
00464                 to "assign" an IndexedColour to a DocColour.
00465     SeeAlso:    DocColour::MakeRefToIndexedColour
00466 
00467 ********************************************************************************************/
00468 
00469 
00470 /********************************************************************************************
00471 
00472 >   ColourModel DocColour::GetColourModel(void) const
00473 
00474     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00475     Created:    30/03/94
00476     Inputs:     -
00477     Outputs:    -
00478     Returns:    A Colour Model identifying the model in which the colour is defined
00479     Purpose:    To determine the colourmodel in which the given colour was defined
00480     Notes:      If this is a reference to an IndexedColour, returns the colour of the
00481                 referenced IndexedColour.
00482                 The colour model number returned may be used as an index into the list
00483                 of ColourContexts held by each document, in order to find a relevant 
00484                 context for the colour.
00485     Errors:     -
00486     SeeAlso:    DocColour::GetSourceColour
00487 
00488 ********************************************************************************************/
00489 
00490 ColourModel DocColour::GetColourModel(void) const
00491 {
00492     ENSURE(Info.SourceColourModel < MAX_COLOURMODELS,
00493             "DocColour based on illegal colour model!");
00494 
00495     // If colour is a reference to an indexed colour, return indexed colour's
00496     // colour model
00497     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
00498     {
00499         ENSURE(SourceColour.Indexed.Colour != NULL,
00500                 "Corrupted DocColour (NULL IndexedColour ref) detected");
00501         return(SourceColour.Indexed.Colour->GetColourModel());
00502     }
00503 
00504     return((ColourModel) Info.SourceColourModel);
00505 }
00506 
00507 
00508 
00509 
00510 /********************************************************************************************
00511 
00512 >   void DocColour::GetSourceColour(ColourGeneric *Result)
00513 
00514     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00515     Created:    30/03/94
00516     Inputs:     Result - pointer to structure to recieve the colour
00517     Outputs:    -
00518     Returns:    The native definition of the colour. This is a ColourPacked containing
00519                 the colour as defined in its original Colour Model (cf DocColour::GetColourModel)
00520     Purpose:    Determine the native definition of the given colour
00521     Notes:      If this is a reference to an IndexedColour, returns the colour of the
00522                 referenced IndexedColour.
00523     Errors:     -
00524     SeeAlso:    DocColour::GetColourModel
00525 
00526 ********************************************************************************************/
00527 
00528 void DocColour::GetSourceColour(ColourGeneric *Result)
00529 {
00530     ENSURE(Info.SourceColourModel < MAX_COLOURMODELS,
00531             "DocColour based on illegal colour model!");
00532 
00533     // If colour is reference to indexed colour, ask the indexed colour for the
00534     // original colour definition, else return our own definition.
00535     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
00536     {
00537         ENSURE(SourceColour.Indexed.Colour != NULL,
00538                 "Corrupted DocColour (NULL IndexedColour ref) detected");
00539         SourceColour.Indexed.Colour->GetSourceColour(Result);
00540     }
00541     else
00542         DEFAULTCONTEXT(Info.SourceColourModel)->
00543                                         UnpackColour(&SourceColour, Result);
00544 
00545     if (Info.ForceRounding)
00546     {
00547         // Our ForceRounding flag is on, so we must round all components to the closest
00548         // half percentage value. This is a bodge to correct for representational errors
00549         // in PANTONE library colours.
00550         double temp;
00551 
00552         temp = Result->Component1.MakeDouble();
00553         temp = (floor((temp * 200.0) + 0.5)) / 200.0;   // Round to nearest 200th
00554         Result->Component1 = temp;
00555 
00556         temp = Result->Component2.MakeDouble();
00557         temp = (floor((temp * 200.0) + 0.5)) / 200.0;   // Round to nearest 200th
00558         Result->Component2 = temp;
00559 
00560         temp = Result->Component3.MakeDouble();
00561         temp = (floor((temp * 200.0) + 0.5)) / 200.0;   // Round to nearest 200th
00562         Result->Component3 = temp;
00563 
00564         temp = Result->Component4.MakeDouble();
00565         temp = (floor((temp * 200.0) + 0.5)) / 200.0;   // Round to nearest 200th
00566         Result->Component4 = temp;
00567     }
00568 }
00569 
00570 
00571 
00572 /********************************************************************************************
00573 
00574 >   void DocColour::SetSeparable(BOOL IsSeparable = TRUE)
00575 
00576     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00577     Created:    30/03/94
00578     Inputs:     IsSeparable -   TRUE if this colour will be allowed to be separated and
00579                                 colour-corrected during conversions
00580                                 FALSE if this colour shouldn't be separated
00581 
00582     Purpose:    To set the separation/correction enable flag for a DocColour.
00583                 Some colours (e.g. EOR blob colours) should not be colour-separated
00584                 on screen. By default, all colours (except StockCols) will separate,
00585                 but this flag can be set on "UI colours" to stop them separating.
00586 
00587     SeeAlso:    DocColour::IsSeparable
00588 
00589 ********************************************************************************************/
00590 
00591 void DocColour::SetSeparable(BOOL IsSeparable)
00592 {
00593     Info.IsSeparable = IsSeparable;
00594 }
00595 
00596 
00597 /********************************************************************************************
00598 
00599 >   void DocColour::SetReservedFlag(UINT32 Value)
00600 
00601     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00602     Created:    12/4/2000
00603     Inputs:     Value - the value to set the flag to
00604 
00605     Purpose:    To set the Reserved flag of the colour info struct. 
00606 
00607     SeeAlso:    My use of this flag can be seen in LineDefinition::ConvertIndexedColours and
00608                 PathProcessorBrush::RenderAttributes.  If you want to use this flag for your
00609                 own purposes I suggest that you take a look at what I've done to make sure
00610                 there will be no conflict.
00611 
00612 ********************************************************************************************/
00613 
00614 void DocColour::SetReservedFlag(UINT32 Value)
00615 {
00616     Info.Reserved = Value;
00617 }
00618 
00619 
00620 /********************************************************************************************
00621 
00622 >   UINT32 DocColour::GetReservedFlag()
00623 
00624     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00625     Created:    12/4/2000
00626     Inputs:     -
00627     Returns:    the Reserved Flag of the ColourInfo struct
00628     Purpose:    access fn.
00629 
00630     SeeAlso:    
00631 
00632 ********************************************************************************************/
00633 
00634 UINT32 DocColour::GetReservedFlag()
00635 {
00636     return Info.Reserved;
00637 }
00638 
00639 
00640 /********************************************************************************************
00641 
00642 >   BOOL DocColour::IsNamed()
00643 
00644     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00645     Created:    12/4/2000
00646     Inputs:     -
00647     Returns:    TRUE, if this colour is named, or if it has the flag set that indicates that it
00648                 was created by a named colour
00649     Purpose:    to identidy if this colour is named, or was created from a named colour.  Note that
00650                 not all colours that were created by Named colours will have the relevant flag set, as
00651                 I have only just started using it (4/2000).  This fn. was really designed to be used
00652                 specifically by the brush attribute replace named colours system.
00653 
00654     SeeAlso:    
00655 
00656 ********************************************************************************************/
00657 
00658 BOOL DocColour::IsNamed()
00659 {
00660     BOOL RetVal = FALSE;
00661     
00662     // first try the parent colour
00663     IndexedColour* pParent = FindParentIndexedColour();
00664     if (pParent != NULL)
00665     {
00666         if (pParent->IsNamed())
00667             RetVal = TRUE;
00668     }
00669     
00670     // now try the flags
00671     if (Info.Reserved == COL_NAMED)
00672         RetVal = TRUE;
00673 
00674     return RetVal;
00675 }
00676 
00677 
00678 /********************************************************************************************
00679 
00680 >   void DocColour::HackColReplacerPreDestruct()
00681 
00682     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00683     Created:    10/6/2000
00684     Inputs:     -
00685     Returns:    -
00686     Purpose:    As you might expect from the name this is a real bodge. Basically the named
00687                 colour replacer used in the brush needs to store some colours which are 
00688                 converted index colours. 
00689                 To cut a long story short I'm looking at a deadline and this prevents an
00690                 assert upon destruction, theres no reason for anyone else to use it.
00691 
00692     SeeAlso:    
00693 
00694 ********************************************************************************************/
00695 
00696 void DocColour::HackColReplacerPreDestruct()
00697 {
00698     Info.SourceColourModel = MAX_COLOURMODELS;
00699 }
00700 
00701 /********************************************************************************************
00702 
00703 >   void DocColour::Mix(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
00704                         ColourContext *BlendContext, BOOL BlendTheLongWay = FALSE,
00705                         ColourContext *OutputContext = NULL)
00706     
00707     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00708     Created:    11/11/94 (moved from constructor, 29/5/96)
00709 
00710     Inputs:     BlendStart - The start DocColour
00711 
00712                 BlendEnd - The end DocColour
00713 
00714                 BlendFraction - The amount by which the two colours should be blended,
00715                 in the range 0.0 to 1.0. Blending is linear in the given colourspace,
00716                 achieved by the equation
00717 
00718                 Result = (BlendStart * (1.0-BlendFraction)) + (BlendEnd * BlendFraction)
00719 
00720                 BlendContext - the colour context in which the blend will take place
00721                                 (may be NULL, but this is NOT recommended)
00722                                 (Note that this is ignored if either colour is a Spot)
00723                                 (Note that if both end colours are CMYK, and Mix effect
00724                                 is used, a CMYK context is used instead, so that CMYK
00725                                 grads colour separate properly)
00726     
00727                 BlendTheLongWay - (ONLY used if the BlendContext points to an HSV context)
00728                 This indicates whether to do 'rainbow' (shortest distance- FALSE) or
00729                 'alt-rainbow' (longest distance- TRUE) HSV colour blending.
00730 
00731                 OutputContext - Normally, this should be NULL. However, if you're doing
00732                 a colour separation involving spot colours, you should pass the output
00733                 colour context in here, so that spots can be correctly separated. The
00734                 output for mixing a spot colour will then be a greyscale ink intensity,
00735                 correctly colour separated, and with its IsSeparable flag FALSE so that
00736                 it is not colour separated or corrected a second time when output. It is
00737                 safe to always pass the output context in here, as this function will
00738                 always work out the appropriate behviour.
00739 
00740     Purpose:    "Constructor" for a DocColour - generates a blended DocColour
00741                 The start and end colours are blended to create this new DocColour. The
00742                 amount by which they are mixed is determined by BlendFraction. The blend
00743                 occurs in the colourspace described by BlendContext. Note that BlendContext
00744                 may be NULL, in which case the default context for the BlendStart colour
00745                 will be used. However, this is not recommended, as this will result in
00746                 a blend which may be incorrect for the context(s) in use in a given
00747                 document, which could give seriously wonky colours!
00748 
00749                 If blending is requested in HSV space, the extra parameter BlendTheLongWay
00750                 is required, to determine if blending is done in a "Rainbow" or "Alt-Rainbow"
00751                 fashion.
00752 
00753     Notes:      Note that although this may be slow, you must mix colours using this
00754                 method, or colour correction/separation may not occur.
00755 
00756                 The blend method specified by BlendContext & BlendTheLongWay is ignored
00757                 if either of the colours is a spot colour - these are always coerced
00758                 into simple "Mix" fills/blends, as otherwise the printed output and
00759                 colour representation on screen will be totally different!
00760 
00761                 If both end colours reference the same IndexedColour, and the mixing
00762                 method is Mix (RGB) or Rainbow (HSV, BlendTheLongWay==FALSE), then all
00763                 intermediate colours are identical, and are thus returned referencing the
00764                 original indexed colour.
00765 
00766                 If both the end colours are tints of the same spot colour, then two things
00767                 can occur:
00768                   * If OutputContext != NULL, we presume the mix is temporary for rendering
00769                     to that context, so produce an RGB mix or separated Ink density value
00770                     for the context.
00771                   * If OutputContext == NULL, we presume you're doing a make shapes on
00772                     a blend or similar, so we create a new local colour for each mix,
00773                     which is a permanent proper tint of the parent spot ink.
00774 
00775 ********************************************************************************************/
00776 
00777 void DocColour::Mix(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
00778                             ColourContext *BlendContext, BOOL BlendTheLongWay,
00779                             ColourContext *OutputContext)
00780 {
00781 //  if (BlendFraction >= 1.0)
00782 //      BlendFraction = 0.999999999;
00783     
00784 //  ERROR3IF(BlendFraction < 0.0 || BlendFraction > 1.0,
00785 //              "DocColour::DocColour Blend: Illegal Blend fraction!");
00786 
00787     ERROR3IF(BlendStart == NULL || BlendEnd == NULL,
00788                 "DocColour::DocColour Blend: NULL input parameters!");
00789 
00790     // Make sure that this colour is not a reference to an IndexedColour, otherwise
00791     // if/when we InitialiseInfoField() below, we'll forget the reference, and trigger
00792     // lots of bogus "IndexedColour deleted while in use" warnings
00793     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
00794     {
00795         SourceColour.Indexed.Colour->DecrementUsage();
00796         Info.SourceColourModel  = COLOURMODEL_RGBT;
00797     }
00798 
00799     // If either the start of end colour is a spot/tint colour, then we will coerce
00800     // this mix into a simple RGB mix, not a Hue mix, by grabbing the default RGB context
00801     // We also special-case a Mix/Rainbow from an IndexedColour to itself, by simply making 
00802     // the mixed step another reference to that colour (but not for alt-rainbow!)
00803     BOOL IncludesSpots = FALSE;         // Remember if we've got to worry about spots
00804 
00805     IndexedColour *StartParent  = BlendStart->FindParentIndexedColour();
00806     IndexedColour *EndParent    = BlendEnd->FindParentIndexedColour();
00807 
00808 
00809     // --- Are blend start/end colours identical? - we might optimise them out if they are
00810     if (StartParent != NULL && StartParent == EndParent)
00811     {
00812         // If it's an RGB Mix or an HSV Rainbow (short way) then all mixes are identical to
00813         // the original colour, so just return that instead.
00814         if ( BlendContext != NULL &&
00815              ( BlendContext->GetColourModel () == COLOURMODEL_RGBT || 
00816              ( BlendContext->GetColourModel () == COLOURMODEL_HSVT && !BlendTheLongWay ) ) )
00817         {
00818             // Make ourselves a reference to the parent colour
00819             MakeRefToIndexedColour ( StartParent );
00820             return;
00821         }
00822     }
00823 
00824 
00825     // --- Determine if one or both of the colours are spot/tint colours
00826     // (When separating, we must treat blends including spot colours very specially)
00827     if (StartParent != NULL && StartParent->IsSpotOrTintOfSpot())
00828         IncludesSpots = TRUE;
00829     else if (EndParent != NULL && EndParent->IsSpotOrTintOfSpot())
00830         IncludesSpots = TRUE;
00831 
00832     if (IncludesSpots)
00833     {
00834         // The blend includes spot colours, so must be coerced into an RGB "Mix"
00835         BlendContext = ColourManager::GetColourContext(COLOURMODEL_RGBT);
00836 
00837         IndexedColour *StartSpot = BlendStart->GetSpotParent();
00838         IndexedColour *EndSpot   = BlendEnd->GetSpotParent();
00839 
00840         if (OutputContext == NULL)
00841         {
00842             // Doing Make Shapes, so should make permanent IndexedColour tints, if
00843             // both the end colours are tints of the same spot colour
00844             if (StartSpot != NULL && StartSpot == EndSpot)
00845             {
00846                 MixTint(StartSpot, StartParent, EndParent, BlendFraction);
00847                 return;
00848             }
00849             // else drop through to normal RGB mixing code (which means the colours
00850             // become process colours. Damn! -- but there's nothing we can do about it)
00851         }
00852         else
00853         {
00854             ColourPlate *ColPlate = OutputContext->GetColourPlate();
00855 
00856             if (ColPlate != NULL && !ColPlate->IsDisabled())
00857             {
00858                 // Make us into a CMYK with the ink value in our Key component
00859                 // The Key is calculated below (in the if statement) but we'll do the common stuff here
00860                 InitialiseInfoField(COLOURMODEL_CMYK);
00861                 SourceColour.CMYK.Cyan = SourceColour.CMYK.Magenta = 
00862                                             SourceColour.CMYK.Yellow = 0;
00863 
00864                 if (ColPlate->GetType() == COLOURPLATE_SPOT)
00865                 {
00866                     // We're rendering to a spot plate, so we want to output an ink density value.
00867                     // Thus, we create a CMYK value, and place the ink density in the Key component.
00868                     // We will then set it non-separable so that it is not separated a second time
00869                     // (see after this if statement)
00870                     // (NOTE: IF both ends are tints of this spot plate, we'll interpolate the tint. If
00871                     // only one end is a spot colour, then the other end will become a 0% tint, i.e. white)
00872 
00873                     // Duh!  We need to check which spot plate we are doing or spot colours end up
00874                     // being printed on all spot plates!
00875 
00876                     IndexedColour* pPlateSpot = ColPlate->GetSpotColour();
00877 
00878                     // Work out the start and end tint values for use with the common ancestor (if any).
00879                     double StartValue = 0.0;
00880                     if (StartSpot != NULL && StartSpot == pPlateSpot)
00881                         StartValue = StartParent->GetAccumulatedTintValue().MakeDouble();
00882 
00883                     double EndValue  = 0.0;
00884                     if (EndSpot != NULL && EndSpot == pPlateSpot)
00885                         EndValue = EndParent->GetAccumulatedTintValue().MakeDouble();
00886 
00887                     // Linearly interpolate the tint values
00888                     double NewTint = (StartValue * (1.0 - BlendFraction)) + (EndValue * (BlendFraction));
00889 
00890                     SourceColour.CMYK.Key = (PColourValue) (NewTint * 255.0);
00891                 }
00892                 else
00893                 {
00894                     // Generate separated RGB versions of the end colours
00895                     ColourRGBT SeparatedStart;
00896                     if (BlendStart->IsTransparent())
00897                         OutputContext->GetWhite((ColourGeneric *) &SeparatedStart);
00898                     else
00899                         OutputContext->ConvertColour(BlendStart, (ColourGeneric *) &SeparatedStart);
00900 
00901                     ColourRGBT SeparatedEnd;
00902                     if (BlendEnd->IsTransparent())
00903                         OutputContext->GetWhite((ColourGeneric *) &SeparatedEnd);
00904                     else
00905                         OutputContext->ConvertColour(BlendEnd, (ColourGeneric *) &SeparatedEnd);
00906 
00907 
00908                     if (ColPlate->IsMonochrome())
00909                     {
00910                         // We're doing a monochrome sep
00911                         // The separated colour should be a greyscale, but let's just check
00912                         ERROR3IF(SeparatedStart.Red != SeparatedStart.Green ||
00913                                  SeparatedStart.Red != SeparatedStart.Blue,
00914                                  "Separated colour is not a greyscale! Doh!");
00915 
00916                         ERROR3IF(SeparatedEnd.Red != SeparatedEnd.Green ||
00917                                  SeparatedEnd.Red != SeparatedEnd.Blue,
00918                                  "Separated colour is not a greyscale! Doh!");
00919 
00920                         // Assuming that R==G==B, use the R levels as ink intensities, and generate
00921                         // this into the Key component
00922                         double temp;
00923                         BlendFraction *= 255.0;
00924                         temp = SeparatedStart.Red.MakeDouble() * (255.0 - BlendFraction);
00925                         temp += SeparatedEnd.Red.MakeDouble() * BlendFraction;
00926                         SourceColour.CMYK.Key = 255 - ((PColourValue) (temp + 0.5));
00927                     }
00928                     else
00929                     {
00930                         // We're doing a colour (e.g. screen preview in shades of Cyan or whatever)
00931                         // separation, so just mix the colour in RGB for previewing)
00932 
00933                         // Override the CMYK setting we just did above!
00934                         InitialiseInfoField(COLOURMODEL_RGBT);
00935 
00936                         // Now, generate an RGB mixed value
00937                         double temp;
00938                         BlendFraction *= 255.0;
00939                         temp = SeparatedStart.Red.MakeDouble() * (255.0 - BlendFraction);
00940                         temp += SeparatedEnd.Red.MakeDouble() * BlendFraction;
00941                         SourceColour.RGBT.Red = (PColourValue) (temp + 0.5);
00942 
00943                         temp = SeparatedStart.Green.MakeDouble() * (255.0 - BlendFraction);
00944                         temp += SeparatedEnd.Green.MakeDouble() * BlendFraction;
00945                         SourceColour.RGBT.Green = (PColourValue) (temp + 0.5);
00946 
00947                         temp = SeparatedStart.Blue.MakeDouble() * (255.0 - BlendFraction);
00948                         temp += SeparatedEnd.Blue.MakeDouble() * BlendFraction;
00949                         SourceColour.RGBT.Blue = (PColourValue) (temp + 0.5);
00950                     }
00951                 }
00952 
00953                 // Finally, set ourselves non-separable so that we are not colour corrected
00954                 // or separated a second time during output!
00955                 SetSeparable(FALSE);
00956 
00957                 // Let's get out of here before we're spotted! (sorry, last bad joke, I promise)
00958                 return;
00959             }
00960             // else drop through to do a normal RGB mix
00961         }
00962         // else drop through to do a normal RGB mix
00963     }
00964 
00965     // --- Check for CMYK -> CMYK fill
00966     // If we're doing an RGB mix and both colours are CMYK, then we will use CMYK mixing
00967     // instead of RGB, so that CMYK grads separate properly
00968     if (BlendContext != NULL && BlendContext->GetColourModel() == COLOURMODEL_RGBT &&
00969             BlendStart->GetColourModel() == COLOURMODEL_CMYK &&
00970             BlendEnd->GetColourModel() == COLOURMODEL_CMYK)
00971     {
00972         BlendContext = ColourManager::GetColourContext(COLOURMODEL_CMYK);
00973     }
00974 
00975 
00976     // OK, so we're not picking at our spots (I lied about that being the last bad joke).
00977     // In that case, do a normal mix
00978     if (BlendContext == NULL)
00979     {
00980         BlendContext = ColourManager::GetColourContext(BlendStart->GetColourModel());
00981         ERROR3IF(BlendContext == NULL, "Can't find a default ColourContext for blend colour space");
00982     }
00983 
00984     switch(BlendContext->GetColourModel())
00985     {
00986         case COLOURMODEL_RGBT:
00987             MixRGB(BlendStart, BlendEnd, BlendFraction, BlendContext);
00988             break;
00989 
00990         case COLOURMODEL_CMYK:
00991             MixCMYK(BlendStart, BlendEnd, BlendFraction, BlendContext);
00992             break;
00993 
00994         case COLOURMODEL_HSVT:
00995             MixHSV(BlendStart, BlendEnd, BlendFraction, BlendContext, BlendTheLongWay);
00996             break;
00997 
00998         default:
00999             ERROR3("DocColour::Mix unimplemented for BlendContext other then RGB or HSV");
01000             break;
01001     }
01002 
01003     // Finally, if both the start and end colour were non-separable, all intermediate
01004     // blended colours will also come out non-separable. This only usually has an effect with
01005     // the "print on all plates" attribute, which overrides the rendering colour with
01006     // special pre-separated greyscales
01007     if (!BlendStart->IsSeparable() && !BlendEnd->IsSeparable())
01008         SetSeparable(FALSE);
01009 }
01010 
01011 
01012 
01013 /********************************************************************************************
01014 
01015 >   void DocColour::MixRGB(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
01016                             ColourContext *BlendContext, ColourContext *OutputContext)
01017     
01018     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01019     Created:    12/6/96
01020 
01021     Inputs:     BlendStart - The start DocColour
01022                 BlendEnd - The end DocColour
01023                 BlendFraction - Blending amount between 0.0 and 1.0
01024                 BlendContext - the RGB colour context in which the blend will take place
01025 
01026     Purpose:    Internal helper function for DocColour::Mix.
01027                 This is a reasonably optimised routine for mixing RGB colours.
01028 
01029     SeeAlso:    DocColour::Mix
01030 
01031 ********************************************************************************************/
01032 
01033 void DocColour::MixRGB(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
01034                             ColourContext *BlendContext)
01035 {
01036     ERROR3IF(BlendStart == NULL || BlendEnd == NULL || BlendContext == NULL, "Illegal NULL params");
01037     ERROR3IF(BlendContext->GetColourModel() != COLOURMODEL_RGBT,
01038              "DocColour::MixRGB is optimised for RGB colours only!");
01039 
01040     InitialiseInfoField(COLOURMODEL_RGBT);
01041 
01042     ColourGeneric StartDef;
01043     if (BlendStart->IsTransparent())                    // If no-colour, then...
01044     {
01045         BlendContext->GetWhite(&StartDef);              // ... use white
01046 
01047         if (BlendEnd->IsTransparent())                  // If both ends no-colour, return no-colour
01048             Info.NoColour = TRUE;
01049     }
01050     else
01051         BlendContext->ConvertColour(BlendStart, &StartDef);     // else use start colour
01052 
01053     // If 0.0 then StartDef now has the colour to use (no blending necessary)
01054     // If BOTH colours are transparent, we will be NoColour, so no need to blend
01055     if (BlendFraction > 0.0 && !Info.NoColour)
01056     {
01057         ColourGeneric EndDef;
01058         if (BlendEnd->IsTransparent())                          // If no-colour then use white
01059             BlendContext->GetWhite(&EndDef);
01060         else
01061             BlendContext->ConvertColour(BlendEnd, &EndDef);
01062 
01063         // Precalculate the blending fractions. Optimisation - Multiply by 255 here to save
01064         // doing it for each component when we convert them into bytes below.
01065         BlendFraction *= 255.0;
01066         const double InverseFraction = (255.0 - BlendFraction);
01067 
01068         double temp;
01069 
01070         // Mix the RGB components into a 0..255 byte, and store into our packed colour definition
01071         temp = StartDef.Component1.MakeDouble() * InverseFraction;
01072         temp += EndDef.Component1.MakeDouble() * BlendFraction;
01073         SourceColour.RGBT.Red = (PColourValue) (temp + 0.5);
01074 
01075         temp = StartDef.Component2.MakeDouble() * InverseFraction;
01076         temp += EndDef.Component2.MakeDouble() * BlendFraction;
01077         SourceColour.RGBT.Green = (PColourValue) (temp + 0.5);
01078 
01079         temp = StartDef.Component3.MakeDouble() * InverseFraction;
01080         temp += EndDef.Component3.MakeDouble() * BlendFraction;
01081         SourceColour.RGBT.Blue = (PColourValue) (temp + 0.5);
01082 
01083         // We don't bother with component 4, as RGB doesn't use it
01084     }
01085     else
01086     {
01087         // Pack the start colour straight into our SourceColour
01088         BlendContext->PackColour(&StartDef, &SourceColour);
01089     }
01090 }
01091 
01092 
01093 
01094 /********************************************************************************************
01095 
01096 >   void DocColour::MixCMYK(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
01097                             ColourContext *BlendContext, ColourContext *OutputContext)
01098     
01099     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01100     Created:    12/6/96
01101 
01102     Inputs:     BlendStart - The start DocColour
01103                 BlendEnd - The end DocColour
01104                 BlendFraction - Blending amount between 0.0 and 1.0
01105                 BlendContext - the RGB colour context in which the blend will take place
01106 
01107     Purpose:    Internal helper function for DocColour::Mix.
01108                 This is a reasonably optimised routine for mixing CMYK colours.
01109 
01110     SeeAlso:    DocColour::Mix
01111 
01112 ********************************************************************************************/
01113 
01114 void DocColour::MixCMYK(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
01115                             ColourContext *BlendContext)
01116 {
01117     ERROR3IF(BlendStart == NULL || BlendEnd == NULL || BlendContext == NULL, "Illegal NULL params");
01118     ERROR3IF(BlendContext->GetColourModel() != COLOURMODEL_CMYK,
01119              "DocColour::MixRGB is optimised for CMYK colours only!");
01120 
01121     InitialiseInfoField(COLOURMODEL_CMYK);
01122 
01123     ColourGeneric StartDef;
01124     if (BlendStart->IsTransparent())                    // If no-colour, then...
01125     {
01126         BlendContext->GetWhite(&StartDef);              // ... use white
01127 
01128         if (BlendEnd->IsTransparent())                  // If both ends no-colour, return no-colour
01129             Info.NoColour = TRUE;
01130     }
01131     else
01132         BlendContext->ConvertColour(BlendStart, &StartDef);     // else use start colour
01133 
01134     // If 0.0 then StartDef now has the colour to use (no blending necessary)
01135     // If BOTH colours are transparent, we will be NoColour, so no need to blend
01136     if (BlendFraction > 0.0 && !Info.NoColour)
01137     {
01138         ColourGeneric EndDef;
01139         if (BlendEnd->IsTransparent())                          // If no-colour then use white
01140             BlendContext->GetWhite(&EndDef);
01141         else
01142             BlendContext->ConvertColour(BlendEnd, &EndDef);
01143 
01144         // Precalculate the blending fractions. Optimisation - Multiply by 255 here to save
01145         // doing it for each component when we convert them into bytes below.
01146         BlendFraction *= 255.0;
01147         const double InverseFraction = (255.0 - BlendFraction);
01148 
01149         double temp;
01150 
01151         // Mix the CMYK components into a 0..255 byte, and store into our packed colour definition
01152         temp = StartDef.Component1.MakeDouble() * InverseFraction;
01153         temp += EndDef.Component1.MakeDouble() * BlendFraction;
01154         SourceColour.CMYK.Cyan = (PColourValue) (temp + 0.5);
01155 
01156         temp = StartDef.Component2.MakeDouble() * InverseFraction;
01157         temp += EndDef.Component2.MakeDouble() * BlendFraction;
01158         SourceColour.CMYK.Magenta = (PColourValue) (temp + 0.5);
01159 
01160         temp = StartDef.Component3.MakeDouble() * InverseFraction;
01161         temp += EndDef.Component3.MakeDouble() * BlendFraction;
01162         SourceColour.CMYK.Yellow = (PColourValue) (temp + 0.5);
01163 
01164         temp = StartDef.Component4.MakeDouble() * InverseFraction;
01165         temp += EndDef.Component4.MakeDouble() * BlendFraction;
01166         SourceColour.CMYK.Key = (PColourValue) (temp + 0.5);
01167     }
01168     else
01169     {
01170         // Pack the start colour straight into our SourceColour
01171         BlendContext->PackColour(&StartDef, &SourceColour);
01172     }
01173 }
01174 
01175 
01176 
01177 /********************************************************************************************
01178 
01179 >   void DocColour::MixHSV(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
01180                             ColourContext *BlendContext, BOOL BlendTheLongWay)
01181     
01182     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01183     Created:    12/6/96
01184 
01185     Inputs:     BlendStart - The start DocColour
01186                 BlendEnd - The end DocColour
01187                 BlendFraction - Blending amount between 0.0 and 1.0
01188                 BlendContext - the HSV colour context in which the blend will take place
01189                 BlendTheLongWay - FALSE for rainbow, TRUE for Alt-Rainbow mixing
01190 
01191     Purpose:    Internal helper function for DocColour::Mix.
01192                 This is a reasonably optimised routine for mixing HSV colours.
01193 
01194     SeeAlso:    DocColour::Mix
01195 
01196 ********************************************************************************************/
01197 
01198 void DocColour::MixHSV(DocColour *BlendStart, DocColour *BlendEnd, double BlendFraction,
01199                             ColourContext *BlendContext, BOOL BlendTheLongWay)
01200 {
01201     ERROR3IF(BlendStart == NULL || BlendEnd == NULL || BlendContext == NULL, "Illegal NULL params");
01202     ERROR3IF(BlendContext->GetColourModel() != COLOURMODEL_HSVT,
01203                  "DocColour::MixHSV is optimised for HSV colours only!");
01204 
01205     InitialiseInfoField(COLOURMODEL_HSVT);
01206 
01207     ColourHSVT StartDef;
01208     if (BlendStart->IsTransparent())                            // If no-colour then use white
01209     {
01210         BlendContext->GetWhite((ColourGeneric *) &StartDef);
01211 
01212         if (BlendEnd->IsTransparent())                          // If both ends no-colour, return no-colour
01213             Info.NoColour = TRUE;
01214     }
01215     else
01216         BlendContext->ConvertColour(BlendStart, (ColourGeneric *) &StartDef);
01217 
01218     // If 0.0 then StartDef now has the colour to use (no blending necessary)
01219     // If BOTH colours are transparent, we will be NoColour, so no need to blend
01220     if (BlendFraction > 0.0 && !Info.NoColour)
01221     {
01222         ColourHSVT EndDef;
01223         if (BlendEnd->IsTransparent())                          // If no-colour then use white
01224             BlendContext->GetWhite((ColourGeneric *) &EndDef);
01225         else
01226             BlendContext->ConvertColour(BlendEnd, (ColourGeneric *) &EndDef);
01227 
01228         if (BlendTheLongWay)
01229         {
01230             // In Alt-rainbow blend, if exaclty one of the colours has undefined hue (it has 0 saturation
01231             // i.e. is black./grey/white), then Gavin decides to go to the Hue of the other colour
01232             // (i.e. do a full rainbow) rather than going to hue 0.
01233             if (StartDef.Saturation.MakeDouble() < 0.01 && EndDef.Saturation.MakeDouble() >= 0.01)
01234             {
01235                 // Start has no hue, but End does, so copy Hue from End
01236                 StartDef.Hue = EndDef.Hue;
01237             }
01238             else if (StartDef.Saturation.MakeDouble() >= 0.01 && EndDef.Saturation.MakeDouble() < 0.01)
01239             {
01240                 // End has no hue, but Start does, so copy Hue from Start
01241                 EndDef.Hue = StartDef.Hue;
01242             }
01243         }
01244 
01245         const double InverseFraction = 1.0 - BlendFraction;
01246 
01247         // HSV blend! We can go 2 ways, as HSV can 'wrap' from 1.0 back to 0.0
01248         BOOL BlendNormally = TRUE;
01249 
01250         // Calc. the "simple" (non-wrapping) distance between the hues
01251         double StartHue     = StartDef.Hue.MakeDouble();
01252         double EndHue       = EndDef.Hue.MakeDouble();
01253 
01254         const double SimpleDist = fabs(StartHue - EndHue);
01255 
01256         // Determine whether we do a simple blend, or we have to "wrap"
01257         if (SimpleDist <= 0.5)
01258             BlendNormally = !(BlendTheLongWay);
01259         else
01260             BlendNormally = BlendTheLongWay;
01261 
01262         // If we have to go the long way, then move the smaller of the two hue
01263         // values up by 360 degrees (1.0) - after blending we'll 'mod' the result
01264         // back down into gamut.
01265         if (!BlendNormally)
01266         {
01267             if (StartHue > EndHue)
01268                 EndHue += 1.0;
01269             else
01270                 StartHue += 1.0;
01271         }
01272 
01273         // Do the blend
01274         double temp;
01275         temp = StartHue * InverseFraction;
01276         temp +=  EndHue * BlendFraction;
01277 
01278         // And if we had to 'wrap', we must 'mod' the value back down into gamut
01279         if (temp > 1.0)
01280             temp -= 1.0;
01281 
01282         StartDef.Hue = temp;
01283 
01284         temp = StartDef.Saturation.MakeDouble() * InverseFraction;
01285         temp +=  EndDef.Saturation.MakeDouble() * BlendFraction;
01286         StartDef.Saturation = temp;
01287 
01288         temp = StartDef.Value.MakeDouble() * InverseFraction;
01289         temp +=  EndDef.Value.MakeDouble() * BlendFraction;
01290         StartDef.Value = temp;
01291     }
01292 
01293     // Pack the colour straight into our SourceColour
01294     BlendContext->PackColour((ColourGeneric *) &StartDef, &SourceColour);
01295 }
01296 
01297 
01298 
01299 /********************************************************************************************
01300 
01301 >   void DocColour::MixTint(IndexedColour *SpotParent, IndexedColour *StartTint,
01302                             IndexedColour *EndTint, double BlendFraction)
01303     
01304     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01305     Created:    20/6/96
01306 
01307     Inputs:     SpotParent  - The IndexedColour which both tints share in common. This
01308                                 MUST be the ultimate spot colour, not a tint half way down
01309                                 the linked chain.
01310 
01311                 StartTint   - The tint colour for the start of the blend. Must be a true
01312                                 tint of SpotParent
01313                 EndTint     - The tint colour for the end of the blend. Must be a true
01314                                 tint of SpotParent
01315 
01316                 BlendFraction - Blending amount between 0.0 and 1.0
01317 
01318     Purpose:    Internal helper function for DocColour::Mix.
01319                 This method is used to mix the DocColours to an IndexedColour result when
01320                 one or both of the end colours are tints. This simply linearly
01321                 interpolates the tint values.
01322 
01323     SeeAlso:    DocColour::Mix
01324 
01325 ********************************************************************************************/
01326 
01327 void DocColour::MixTint(IndexedColour *SpotParent, IndexedColour *StartTint,
01328                         IndexedColour *EndTint, double BlendFraction)
01329 {
01330     ERROR3IF(SpotParent == NULL || StartTint == NULL || EndTint == NULL,
01331                 "Illegal NULL params");
01332 
01333     ERROR3IF(SpotParent->GetType() != COLOURTYPE_SPOT, "SpotParent must be a spot colour!");
01334 
01335     ERROR3IF(!StartTint->IsSpotOrTintOfSpot(), "StartTint must be a true tint!");
01336     ERROR3IF(!EndTint->IsSpotOrTintOfSpot(), "EndTint must be a true tint!");
01337 
01338     ColourList *ColList = ColourManager::GetCurrentColourList();
01339     if (ColList == NULL)
01340     {
01341         ERROR3("No current colour list?!");
01342         return;
01343     }
01344 
01345     IndexedColour *MixedLocal = new IndexedColour;
01346     if (MixedLocal == NULL)
01347     {
01348         ERROR3("Couldn't create IndexedColour local mix");
01349         return;
01350     }
01351 
01352     // Work out the start and end tint values _for use with the common ancestor_.
01353     double StartValue = StartTint->GetAccumulatedTintValue().MakeDouble();
01354     double EndValue  = EndTint->GetAccumulatedTintValue().MakeDouble();
01355 
01356     // Linearly interpolate the tint values
01357     double NewTint = (StartValue * (1.0 - BlendFraction)) + (EndValue * (BlendFraction));
01358 
01359     // Fill in the new local colour appropriately
01360     MixedLocal->SetLinkedParent(SpotParent, COLOURTYPE_TINT);
01361     MixedLocal->SetTintValue(NewTint);
01362     MixedLocal->SetUnnamed();       // Ensure it's unnamed (local)
01363 
01364     // Add the local colour to the unnamed colour list
01365     ColList->AddItem(MixedLocal);
01366 
01367     // And make this DocColour reference the new local
01368     MakeRefToIndexedColour(MixedLocal);
01369 }
01370 
01371 /********************************************************************************************
01372 
01373 >   DocColour::DocColour& operator=(const DocColour& Other)
01374 
01375     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01376     Created:    14/04/94
01377     Inputs:     Other - colour to copy
01378     Outputs:    -
01379     Returns:    
01380     Purpose:    DocColour assignment operator
01381     Notes:      If copying a reference to an indexed colour, the indexed colours
01382                 usage count will be incremented.
01383                 If this is already a reference to an indexed colour, that indexed
01384                 colours usage count will be decremented.
01385 
01386                 NOTE - SUPER IMPORTANT!
01387                 This requires that the DocColour has been initialised by its 
01388                 constructor! You cannot thus treat an area of uninitialised memory
01389                 as a DocColour and then try to initialise it using the copy constructor,
01390                 as this could cause a fatal attempt to dereference a pointer.
01391                 (This will hopefully be trapped by ENSURES)
01392 
01393                 If you need to initialise such a chunk of memory as a DocColour,
01394                 then you'll need to call the Constructor in a special way. Ask Tim
01395                 for details of how to do this.
01396     Errors:     -
01397 
01398 ********************************************************************************************/
01399 
01400 DocColour& DocColour::operator=(const DocColour& Other)
01401 {
01402     ENSURE(Info.SourceColourModel < MAX_COLOURMODELS,
01403             "Attempt to use illegal colour model!");
01404 
01405     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01406     {
01407         ENSURE(SourceColour.Indexed.Colour != NULL,
01408                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01409 
01410         CC_ASSERT_VALID(SourceColour.Indexed.Colour);
01411 
01412         SourceColour.Indexed.Colour->DecrementUsage();
01413     }
01414 
01415     Info = Other.Info;
01416     CachedColour = Other.CachedColour;
01417     SourceColour = Other.SourceColour;
01418 
01419     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01420     {
01421         ENSURE(SourceColour.Indexed.Colour != NULL,
01422                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01423 
01424         SourceColour.Indexed.Colour->IncrementUsage();
01425         ENSURE(Info.CacheColourModel == 0, "RefToIndexedColour DocColour has a cache!!");
01426 
01427 #ifdef TRACECOLOURIX
01428 TRACE( _T(">> DocColour @ %x = (DocColour => ColourIx %x)\n"), (INT32)this, (INT32)SourceColour.Indexed.Colour);
01429 #endif
01430     }
01431 
01432     return(*this);
01433 }
01434 
01435 /********************************************************************************************
01436 
01437 >   void DocColour::MakeRefToIndexedColour(IndexedColour *Other)
01438 
01439     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01440     Created:    03/05/94
01441     Inputs:     Other - Indexed colour to assign
01442     Outputs:    -
01443     Returns:    
01444     Purpose:    DocColour assignment - Makes this DocColour a reference to the
01445                 given Indexed Colour. The Indexed Colour cannot be deleted until
01446                 this DocColour releases this claim upon it (which occurs when it is
01447                 deleted or re-assigned)
01448 
01449     Notes:      This is not done as an "operator=" because it does NOT make an
01450                 independent copy of the other colour, merely a reference to it;
01451                 I force you to use this method in order to remind you of this.
01452                 This makes the given DocColour a reference to an Indexed Colour,
01453                 incrementing the usage count of that indexed colour.
01454                 If this is already a reference to an indexed colour, that indexed
01455                 colours usage count will be decremented.
01456 
01457     Errors:     -
01458     SeeAlso:    DocColour:FindParentIndexedColour
01459 
01460 ********************************************************************************************/
01461 
01462 // ---------
01463 // Special debugging code to help track down IndexedColour usage 'leaks'
01464 // Set 'TRACECOLOURIX' at the top of this file if you want tracking information
01465 // spewing out into your trace stream.
01466 void DocColour::MakeRefToIndexedColourDBG(IndexedColour *Other, LPCSTR TheFile, INT32 TheLine)
01467 {
01468 #ifdef TRACECOLOURIX
01469     TRACE( _T(">> DocColour @ %x ref ColourIx: %x @ %s line %ld\n"), (INT32)this, (INT32)Other, TheFile, TheLine);
01470 #endif
01471 
01472 // Disable the debugging macro so that the function code will compile
01473 #undef MakeRefToIndexedColour
01474 // ---------
01475 
01476     MakeRefToIndexedColour(Other);
01477 }
01478 
01479 
01480 
01481 void DocColour::MakeRefToIndexedColour(IndexedColour *Other)
01482 {
01483     ENSURE(Other != NULL,
01484         "NULL IndexedColour pointer passed to DocColour::MakeRefToIndexedColour!");
01485 
01486     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01487     {
01488         ENSURE(SourceColour.Indexed.Colour != NULL,
01489                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01490         SourceColour.Indexed.Colour->DecrementUsage();
01491     }
01492 
01493     Info.NoColour           = FALSE;
01494     Info.SourceColourModel  = COLOURMODEL_INDEXED;
01495     Info.CacheColourModel   = COLOURMODEL_NOTCACHED;    // NEVER cache indexed colours
01496     Info.OCContextHandle    = 0;
01497     Info.IsSeparable        = TRUE;                     // IxCols are always separable
01498 
01499     SourceColour.Indexed.Colour = Other;
01500     Other->IncrementUsage();
01501 }
01502 
01503 
01504 
01505 /********************************************************************************************
01506 
01507 >   IndexedColour *DocColour::GetSpotParent(void)
01508 
01509     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01510     Created:    25/6/96
01511 
01512     Returns:    NULL if this DocColour does not reference an indexed colour, or if the
01513                 referenced colour is not a spot colour, else
01514                 A pointer to the ultimate parent spot colour of this colour.
01515 
01516     Purpose:    To determine which spot colour (if any) is the ultimate spot colour
01517                 parent of this DocColour. (i.e. to see which spot plate a DocColour
01518                 will appear on).
01519 
01520     Notes:      This only returns a non-NULL result if this colour is a TRUE tint of
01521                 a spot colour (as opposed to a tint of a process colour).
01522 
01523 ********************************************************************************************/
01524 
01525 IndexedColour *DocColour::GetSpotParent(void)
01526 {
01527     IndexedColour *Parent = FindParentIndexedColour();
01528     if (Parent != NULL)
01529     {
01530         if (!Parent->IsSpotOrTintOfSpot())          // If we aren't a TRUE tint, return NULL
01531             return(NULL);
01532 
01533         Parent = Parent->FindOldestAncestor();      // ...else find our spot parent
01534         if (Parent->IsSpotOrTintOfSpot())           // (and check just to be really safe)
01535             return(Parent);
01536     }
01537 
01538     // no parent, or it's not a spot colour
01539     return(NULL);
01540 }
01541 
01542 /********************************************************************************************
01543 
01544 >   BOOL DocColour::operator==(const DocColour Other) const
01545 
01546     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01547     Created:    14/04/94
01548     Inputs:     Other - colour to compare ourselves against
01549     Outputs:    -
01550     Returns:    TRUE if we are 'identical' to the other colour.
01551 
01552     Purpose:    DocColour comparison operator
01553 
01554     Notes:      When comparing 2 colours, they will be considered equal if:
01555                 * They are both 'no colour' (fully transparent), or
01556                 * They are *exactly* equal, i.e. the same colour defined in the same
01557                   colour model (Pure RGB red is NOT equal to pure HSV red)
01558 
01559                 Note that for this comparison, references to indexedcolours
01560                 are compared as references, i.e. it does NOT compare the definitions
01561                 of IndexedColours, only the pointer to the IndexedColours (so 
01562                 IndexedColour references are essentially treated as another colour model)
01563 
01564     Errors:     -
01565     SeeAlso:    DocColour::GetColourModel
01566 
01567 ********************************************************************************************/
01568 
01569 BOOL DocColour::operator==(const DocColour Other) const
01570 {
01571     if (Info.NoColour && Other.Info.NoColour)
01572         return(TRUE);
01573 
01574     return (Info.NoColour == Other.Info.NoColour &&
01575             Info.SourceColourModel == Other.Info.SourceColourModel &&
01576             memcmp(&SourceColour, &Other.SourceColour, sizeof(ColourPacked)) == 0 );
01577 }
01578 
01579 
01580 
01581 /********************************************************************************************
01582 
01583 >   BOOL DocColour::operator!=(const DocColour Other) const
01584 
01585     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01586     Created:    14/04/94
01587     Inputs:     Other - colour to compare ourselves against
01588     Outputs:    -
01589     Returns:    FALSE if we are identical to the other colour. NOTE that this
01590                 will only be the case if we are both defined in the same colour
01591                 model (i.e. pure red defined in HSVT is NOT equal to pure red in RGBT)
01592     Purpose:    DocColour comparison operator
01593     Notes:      If comparing two references to indexed colours, they will only
01594                 be considered equal if they reference the SAME indexed colour
01595                 (i.e. we do not compare the indexed colours)
01596     Errors:     -
01597     SeeAlso:    DocColour::GetColourModel
01598 
01599 ********************************************************************************************/
01600 
01601 BOOL DocColour::operator!=(const DocColour Other) const
01602 {
01603     return (Info.NoColour != Other.Info.NoColour ||
01604             Info.SourceColourModel != Other.Info.SourceColourModel ||
01605             memcmp(&SourceColour, &Other.SourceColour, sizeof(ColourPacked)) != 0 );
01606 }
01607 
01608 // ---------------------------------------------------------------------------------------
01609 // Functions below this point have been left in purely for backward compatability with the
01610 // old colour system. They may be removed in the future if they are found to be unused.
01611 
01612 DocColour::DocColour(INT32 Red, INT32 Green, INT32 Blue)
01613 {
01614     ZapSourceColour();
01615     InitialiseInfoField(COLOURMODEL_RGBT);
01616 
01617     SourceColour.RGBT.Red   = (PColourValue) Red;
01618     SourceColour.RGBT.Green = (PColourValue) Green;
01619     SourceColour.RGBT.Blue  = (PColourValue) Blue;
01620     SourceColour.RGBT.Transparent = 0;
01621 }
01622 
01623 
01624 
01625 void DocColour::SetRGBValue(INT32 Red, INT32 Green, INT32 Blue)
01626 // NOTE that this forces our colourmodel to RGBT.
01627 {
01628     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01629     {
01630         ENSURE(SourceColour.Indexed.Colour != NULL,
01631                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01632         SourceColour.Indexed.Colour->DecrementUsage();
01633     }
01634 
01635     InitialiseInfoField(COLOURMODEL_RGBT);
01636 
01637     SourceColour.RGBT.Red   = (PColourValue) Red;
01638     SourceColour.RGBT.Green = (PColourValue) Green;
01639     SourceColour.RGBT.Blue  = (PColourValue) Blue;
01640     SourceColour.RGBT.Transparent = 0;  
01641 }
01642 
01643 
01644 void DocColour::GetRGBValue(INT32* Red, INT32* Green, INT32* Blue)
01645 {
01646     ColourContextRGBT *CCrgbt = (ColourContextRGBT *)ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
01647     ColourRGBT result;
01648     ColourPacked bob;
01649 
01650     CCrgbt->ConvertColour((DocColour *)this, (ColourGeneric *)&result);
01651     CCrgbt->PackColour((ColourGeneric *)&result, (ColourPacked *)&bob);
01652 
01653     *Red    = (INT32) bob.RGBT.Red;
01654     *Green  = (INT32) bob.RGBT.Green;
01655     *Blue   = (INT32) bob.RGBT.Blue;
01656 }
01657 
01658 
01659 void DocColour::SetHSVValue(INT32 h, INT32 s, INT32 v)
01660 // NOTE that this forces our colourmodel to HSVT.
01661 {
01662     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01663     {
01664         ENSURE(SourceColour.Indexed.Colour != NULL,
01665                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01666         SourceColour.Indexed.Colour->DecrementUsage();
01667     }
01668 
01669     InitialiseInfoField(COLOURMODEL_HSVT);
01670 
01671     SourceColour.HSVT.Hue           = (PColourValue) h;
01672     SourceColour.HSVT.Saturation    = (PColourValue) s;
01673     SourceColour.HSVT.Value         = (PColourValue) v;
01674     SourceColour.HSVT.Transparent   = 0;    
01675 }
01676 
01677 
01678 void DocColour::GetHSVValue(INT32* h, INT32* s, INT32* v)
01679 {
01680     ColourContextHSVT *CChsvt = (ColourContextHSVT *)ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
01681     ColourHSVT result;
01682     ColourPacked bob;
01683 
01684     CChsvt->ConvertColour((DocColour *)this, (ColourGeneric *)&result);
01685     CChsvt->PackColour((ColourGeneric *)&result, (ColourPacked *)&bob);
01686 
01687     *h  = (INT32) bob.HSVT.Hue;
01688     *s  = (INT32) bob.HSVT.Saturation;
01689     *v  = (INT32) bob.HSVT.Value;
01690 }
01691 
01692 
01693 void DocColour::SetCMYKValue(PColourCMYK *New)
01694 {
01695     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01696     {
01697         ENSURE(SourceColour.Indexed.Colour != NULL,
01698                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01699         SourceColour.Indexed.Colour->DecrementUsage();
01700     }
01701 
01702     InitialiseInfoField(COLOURMODEL_CMYK);
01703 
01704     memcpy(&SourceColour, New, sizeof(PColourCMYK));
01705 }
01706 
01707 
01708 void DocColour::GetCMYKValue(PColourCMYK *Result)
01709 {
01710     ColourContext *CCcmyk = ColourContext::GetGlobalDefault(COLOURMODEL_CMYK);
01711     CCcmyk->ConvertColour(this, (ColourPacked *) Result);
01712 }
01713 
01714 
01715 void DocColour::GetCMYKValue(ColourContext* pContext, PColourCMYK *Result)
01716 {
01717     if (pContext!=NULL)
01718     {
01719         ERROR3IF(pContext->GetColourModel() != COLOURMODEL_CMYK, "Colour context is not CMYK!");
01720         pContext->ConvertColour(this, (ColourPacked *) Result);
01721         return;
01722     }
01723 
01724     ColourContext *CCcmyk = ColourContext::GetGlobalDefault(COLOURMODEL_CMYK);
01725     ERROR3IF(CCcmyk == NULL, "No default CMYK colour context?!");
01726 
01727     CCcmyk->ConvertColour(this, (ColourPacked *) Result);
01728 }
01729 
01730 
01731 
01732 void DocColour::GetDebugDetails(StringBase* Str)
01733 {
01734     String_256 TempStr;
01735 
01736     if (Info.IsSeparable)
01737         *Str += TEXT(" Sep ");
01738     else
01739         *Str += TEXT(" NotSep ");
01740 
01741     if (Info.SourceColourModel == COLOURMODEL_INDEXED)
01742     {
01743         ENSURE(SourceColour.Indexed.Colour != NULL,
01744                 "Corrupted DocColour (NULL IndexedColour ref) detected");
01745 
01746         String_64 *pIndexedName = SourceColour.Indexed.Colour->GetName();
01747 //      TempStr._MakeMsg(TEXT(" (#1%s) ref->"), 
01748 //                       pIndexedName); // This is a reference to an indexed col
01749 //      (*Str) += TempStr;
01750         (*Str) += TEXT(" (");
01751         (*Str) += (*pIndexedName);
01752         (*Str) += TEXT(") ref ->");
01753         SourceColour.Indexed.Colour->GetDebugDetails(Str);
01754         return;
01755     }
01756         
01757 
01758     if (Info.NoColour)
01759         TempStr._MakeMsg( TEXT(" colour=transparent\r\n"));
01760     else
01761     {       
01762         ColourContext *cc = ColourContext::GetGlobalDefault((ColourModel) Info.SourceColourModel);
01763         ColourGeneric col;
01764 
01765         String_32 ModelName;
01766         cc->GetModelName(&ModelName);
01767         cc->UnpackColour(&SourceColour, &col);
01768 
01769         TempStr._MakeMsg( TEXT(" colour=#1%s(#2%ld, #3%ld, #4%ld, #5%ld)\r\n"), (TCHAR *) ModelName,
01770                             (INT32) (col.Component1.MakeDouble()*100), (INT32) (col.Component2.MakeDouble()*100),
01771                             (INT32) (col.Component3.MakeDouble()*100), (INT32) (col.Component4.MakeDouble()*100));
01772     }
01773 
01774     (*Str) += TempStr;
01775 }

Generated on Sat Nov 10 03:45:02 2007 for Camelot by  doxygen 1.4.4