00001 // $Id: brushref.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 00099 // BrushRef implementation 00100 00101 00102 #include "camtypes.h" 00103 #include "brushref.h" 00104 #include "nodebldr.h" 00105 //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 //#include "doccoord.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 #include "nodebldr.h" 00110 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 #include "nodepath.h" 00112 //#include "nodecomp.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "gblend.h" 00114 #include "nodeblnd.h" 00115 #include "nodeclip.h" 00116 #include "lineattr.h" 00117 #include "attrmap.h" 00118 00119 CC_IMPLEMENT_MEMDUMP(BrushRef, BlendRef) 00120 CC_IMPLEMENT_MEMDUMP(BrushRefBlender, CC_CLASS_MEMDUMP); 00121 00122 #define DELPTR(p) if (p != NULL) { delete p; p = NULL; } 00123 #define FLATNESS 1024 00124 00125 // Declare smart memory handling in Debug builds 00126 #define new CAM_DEBUG_NEW 00127 00128 /*********************************************************************************************** 00129 00130 > void BlendPathOffset::CalculateAngleAndMagnitude() 00131 00132 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00133 Created: 7/12/99 00134 Inputs: - 00135 Outputs: - 00136 Returns: - 00137 Purpose: takes the x and y offset members and calculates the angle and magnitude of that vector 00138 00139 ***********************************************************************************************/ 00140 00141 void BlendPathOffset::CalculateAngleAndMagnitude() 00142 { 00143 MILLIPOINT Xsq = m_XOffset * m_XOffset; 00144 MILLIPOINT Ysq = m_YOffset * m_YOffset; 00145 double Hypotenuse = sqrt((double)Xsq + (double)Ysq); 00146 double Calc = ((double)m_XOffset / Hypotenuse); 00147 double RadAngle = acos(Calc); 00148 // double DegAngle = RadAngle * (180 / PI); 00149 00150 m_Angle = RadAngle; 00151 m_Magnitude = (MILLIPOINT)Hypotenuse; 00152 } 00153 00154 00155 /*********************************************************************************************** 00156 00157 > void BlendPathOffset::GetAngleAndMagnitude(double* pAngle, MILLIPOINT* pMagnitude) 00158 00159 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00160 Created: 7/12/99 00161 Inputs: - 00162 Outputs: pAngle 00163 pMagnitude 00164 Returns: - 00165 Purpose: to get the angle and magnitude of this vector 00166 00167 ***********************************************************************************************/ 00168 00169 void BlendPathOffset::GetAngleAndMagnitude(double* pAngle, MILLIPOINT* pMagnitude) 00170 { 00171 *pAngle = m_Angle; 00172 *pMagnitude = m_Magnitude; 00173 } 00174 00175 00176 /*********************************************************************************************** 00177 00178 > void BlendPathOffset::RotateByAngle(double Angle, MILLIPOINT* pXOffset, MILLIPOINT* pYOffset) 00179 00180 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00181 Created: 7/12/99 00182 Inputs: Angle - the angle to rotate by 00183 Outputs: pXOffset - the resulting scalar value of the vector 00184 pYOffset 00185 Returns: - 00186 Purpose: to find out the x and y offset values if this blendpathoffset were to be rotated 00187 by the given angle 00188 00189 ***********************************************************************************************/ 00190 00191 void BlendPathOffset::RotateByAngle(double Angle, MILLIPOINT* pXOffset, MILLIPOINT* pYOffset) 00192 { 00193 double NewAngle = m_Angle + Angle; 00194 00195 *pXOffset = (MILLIPOINT)(m_Magnitude * cos(NewAngle)); 00196 *pYOffset = (MILLIPOINT)(m_Magnitude * sin(NewAngle)); 00197 } 00198 00199 00200 00201 /*********************************************************************************************** 00202 00203 > BrushRef::BrushRef() 00204 00205 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00206 Created: 7/12/99 00207 Inputs: - 00208 Outputs: - 00209 Returns: - 00210 Purpose: Default constructor. 00211 00212 ***********************************************************************************************/ 00213 00214 BrushRef::BrushRef() 00215 { 00216 m_pNode = NULL; 00217 m_NumBlendPaths = 0; 00218 m_pBlendPathAttrMap = NULL; 00219 m_CachedRect = DocRect(0,0,0,0); 00220 m_pCurrentBlendPath = NULL; 00221 } 00222 00223 /*********************************************************************************************** 00224 00225 > BrushRef::~BrushRef() 00226 00227 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00228 Created: 12/10/94 00229 Inputs: - 00230 Outputs: - 00231 Returns: - 00232 Purpose: Default destructor. 00233 00234 ***********************************************************************************************/ 00235 00236 BrushRef::~BrushRef() 00237 { 00238 FreeAttributes(); 00239 m_BlendPathList.DeleteAll(); 00240 m_OffsetList.clear(); 00241 } 00242 00243 /*********************************************************************************************** 00244 00245 > BOOL BrushRef::Initialise(NodeRenderableInk* pInitNode) 00246 00247 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00248 Created: 7/12/99 00249 Inputs: pInitNode = ptr to the node this BrushRef refers to. 00250 00251 Outputs: - 00252 Returns: TRUE if successfully initialises, FALSE otherwise 00253 Purpose: This inits the BrushRef object with the given node. Essentially a wrapper for 00254 the blendref initialise function. However it also works out 00255 the blendpath offsets, if there are any 00256 00257 ***********************************************************************************************/ 00258 00259 BOOL BrushRef::Initialise(NodeRenderableInk* pInitNode) 00260 { 00261 ERROR2IF(pInitNode == NULL, FALSE, "Ink node is NULL in BrushRef::Initialise"); 00262 00263 // Note that BrushDefinition::GenerateBrush now prevents objects with brush attributes being 00264 // used to generate brushes, instead it converts them to groups of nodepaths as per Convert Line to Shapes 00265 00266 pInitNode->MakeAttributeComplete(); // just in case we're missing any 00267 00268 BOOL ok = BlendRef::InitialiseForBrush(pInitNode); 00269 00270 if (ok) 00271 { 00272 // if we have made a brushref from a group then the different 00273 // blendpaths will be offset from the centre of. work out these 00274 // offsets and store them in a list 00275 m_OffsetList.clear(); 00276 DocRect BRect = GetBoundingRect(); 00277 DocCoord Centre = BRect.Centre(); 00278 00279 BlendPath* pBlendPath = GetFirstBlendPath(); 00280 00281 while (pBlendPath != NULL) 00282 { 00283 Path* pPath = pBlendPath->GetPath(); 00284 if (pPath) 00285 { 00286 DocRect BlendPathRect = pPath->GetBoundingRect(); 00287 DocCoord BlendPathCentre = BlendPathRect.Centre(); 00288 00289 BlendPathOffset ThisOffset; 00290 ThisOffset.m_XOffset = BlendPathCentre.x - Centre.x ; 00291 ThisOffset.m_YOffset = BlendPathCentre.y - Centre.y; 00292 ThisOffset.CalculateAngleAndMagnitude(); 00293 m_OffsetList.push_back(ThisOffset); 00294 pBlendPath->FindAppliedAttributes(); 00295 pBlendPath = GetNextBlendPath(pBlendPath); 00296 } 00297 else 00298 { 00299 ERROR3("BlendPath has no path"); 00300 return FALSE; 00301 } 00302 } 00303 // if we have a bitmap fill we need to do some special things.. 00304 SetBitmapFillFlags(); 00305 PreBlend(); 00306 if (pInitNode->IsABlend()) 00307 ((NodeBlend*)pInitNode)->Deinit(); 00308 return TRUE; 00309 } 00310 00311 00312 return FALSE; 00313 00314 } 00315 00316 00317 /*********************************************************************************************** 00318 00319 > BOOL BrushRef::MakeCopiesForRendering() 00320 00321 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00322 Created: 12/9/2000 00323 Inputs: - 00324 Outputs: - 00325 Returns: TRUE if successful, FALSE otherwise (e.g. out of memory) 00326 00327 Purpose: Asks the blendpaths to make copies of their paths and attributes which 00328 we will use to render with 00329 00330 ***********************************************************************************************/ 00331 00332 BOOL BrushRef::MakeCopiesForRendering() 00333 { 00334 // BlendPath* pLastPath = NULL; 00335 BlendPath* pBlendPath = GetFirstBlendPath(); 00336 BOOL ok = TRUE; 00337 while (pBlendPath != NULL) 00338 { 00339 if (ok) 00340 ok = pBlendPath->MakeCopyPathAndAttributes(); 00341 pBlendPath = GetNextBlendPath(pBlendPath); 00342 00343 } 00344 return ok; 00345 00346 } 00347 00348 00349 /*********************************************************************************************** 00350 00351 > BOOL BrushRef::UpdateCopies() 00352 00353 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00354 Created: 14/01/2004 00355 Inputs: - 00356 Outputs: - 00357 Returns: TRUE if successful, FALSE otherwise (e.g. out of memory) 00358 00359 Purpose: Asks the blendpaths to make copies of their paths and attributes which 00360 we will use to render with 00361 00362 ***********************************************************************************************/ 00363 00364 BOOL BrushRef::UpdateCopies() 00365 { 00366 // BlendPath* pLastPath = NULL; 00367 BlendPath* pBlendPath = GetFirstBlendPath(); 00368 BOOL ok = TRUE; 00369 while (pBlendPath != NULL && ok) 00370 { 00371 pBlendPath->UpdateCopyPathAndAttributes(); 00372 pBlendPath = GetNextBlendPath(pBlendPath); 00373 00374 } 00375 return ok; 00376 00377 } 00378 00379 00380 /*********************************************************************************************** 00381 00382 > BOOL BrushRef::MakeCopiesForRendering() 00383 00384 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00385 Created: 12/9/2000 00386 Inputs: - 00387 Outputs: - 00388 Returns: - 00389 00390 Purpose: Asks the blendpaths to delete the copies of paths and attributes 00391 00392 ***********************************************************************************************/ 00393 00394 void BrushRef::DeleteRenderCopies() 00395 { 00396 // BlendPath* pLastPath = NULL; 00397 BlendPath* pBlendPath = GetFirstBlendPath(); 00398 while (pBlendPath != NULL) 00399 { 00400 pBlendPath->DeleteCopyPathAndAttributes(); 00401 pBlendPath = GetNextBlendPath(pBlendPath); 00402 00403 } 00404 } 00405 00406 00407 /*********************************************************************************************** 00408 00409 > Path* BrushRef::GetFirstCopyPath() 00410 00411 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00412 Created: 12/9/2000 00413 Inputs: - 00414 Outputs: - 00415 Returns: the copy of the path made by the first blendpath that we should use for 00416 rendering 00417 00418 Purpose: Makes the first blendpath our current blendpath member and returns the 00419 copy of its path. 00420 Basically you should use the system like this: 00421 00422 00423 Path* pPath = pBrushRef->GetFirstCopyPath(); 00424 CCAttrMap* pMap = NULL; 00425 00426 while (pPath) 00427 { 00428 pMap = pBrushRef->GetCurrentAttributeCopy(); 00429 00430 pMap->Render(or whatever) 00431 pPath->Render (or whatever) 00432 00433 pPath = pBrushRef->GetNextCopyPath(); 00434 } 00435 00436 ***********************************************************************************************/ 00437 00438 Path* BrushRef::GetFirstCopyPath() 00439 { 00440 m_pCurrentBlendPath = GetFirstBlendPath(); 00441 if (m_pCurrentBlendPath == NULL) 00442 { 00443 ERROR3("First blendpath is NULL in BrushRef::GetFirstCopyPath"); 00444 return NULL; 00445 } 00446 return m_pCurrentBlendPath->GetCopyPath(); 00447 } 00448 00449 00450 /*********************************************************************************************** 00451 00452 > Path* BrushRef::GetFirstCopyPath() 00453 00454 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00455 Created: 12/9/2000 00456 Inputs: - 00457 Outputs: - 00458 Returns: the next path to be rendered 00459 00460 Purpose: Increments our current blendpath member and returns the copy path of 00461 the next blendpath 00462 00463 ***********************************************************************************************/ 00464 00465 Path* BrushRef::GetNextCopyPath() 00466 { 00467 // If our current blendpath isn't set yet then its an error 00468 if (m_pCurrentBlendPath == NULL) 00469 { 00470 ERROR3("Current blendpath is NULL in BrushRef::GetNextCopyPath"); 00471 return NULL; 00472 } 00473 m_pCurrentBlendPath = GetNextBlendPath(m_pCurrentBlendPath); 00474 00475 if (m_pCurrentBlendPath != NULL) 00476 return m_pCurrentBlendPath->GetCopyPath(); 00477 00478 // we've hit the end of the line 00479 return NULL; 00480 } 00481 00482 00483 00484 /*********************************************************************************************** 00485 00486 > CCAttrMap* BrushRef::GetCurrentAttributeCopy() 00487 00488 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00489 Created: 12/9/2000 00490 Inputs: - 00491 Outputs: - 00492 Returns: the attribute map that we should render with our current copy path 00493 00494 Purpose: 00495 00496 ***********************************************************************************************/ 00497 00498 CCAttrMap* BrushRef::GetCurrentAttributeCopy() 00499 { 00500 if (m_pCurrentBlendPath == NULL) 00501 { 00502 ERROR3("Current blendpath is NULL in BrushRef::GetCurrentAttributeCopy"); 00503 return NULL; 00504 } 00505 return m_pCurrentBlendPath->GetCopyAttributes(); 00506 00507 } 00508 00509 /*********************************************************************************************** 00510 00511 > MILLIPOINT BrushRef::GetFirstOffset(POSITION* pHeadPosition) 00512 00513 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00514 Created: 7/12/99 00515 Inputs: pListPosition - uninitialised POSITION variable 00516 Outputs: pListPosition - the position of the head of the list - use it to pass into GetNextOffset 00517 Returns: the value of the first offset in the m_offset list. If the list is empty it 00518 returns -1. 00519 Purpose: as above 00520 00521 ***********************************************************************************************/ 00522 00523 BlendPathOffset *BrushRef::GetFirstOffset( iterator *pHeadPosition ) 00524 { 00525 if (m_OffsetList.empty()) 00526 return NULL; 00527 else 00528 { 00529 *pHeadPosition = m_OffsetList.begin(); 00530 return &( *(*pHeadPosition)++ ); 00531 } 00532 } 00533 00534 00535 /*********************************************************************************************** 00536 00537 > MILLIPOINT BrushRef::GetNextOffset(POSITION* pPosition) 00538 00539 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00540 Created: 7/12/99 00541 Inputs: pPosition - the position to get in the list 00542 Outputs: pPosition - the next position in the list (or NULL) 00543 Returns: the value of the next offset in the m_offset list. If the list is empty it 00544 returns NULL. 00545 Purpose: as above 00546 00547 ***********************************************************************************************/ 00548 00549 BlendPathOffset* BrushRef::GetNextOffset( iterator *pHeadPosition ) 00550 { 00551 if( m_OffsetList.empty() ) 00552 return NULL; 00553 else 00554 return &( *(*pHeadPosition)++ ); 00555 } 00556 00557 00558 /*********************************************************************************************** 00559 00560 > DocRect BrushRef::GetBoundingRect() 00561 00562 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00563 Created: 7/12/99 00564 Inputs: 00565 Outputs: 00566 Returns: the bounding rect of this brushref 00567 Purpose: as above, unions the bounding boxes 00568 00569 ***********************************************************************************************/ 00570 00571 DocRect BrushRef::GetBoundingRect() 00572 { 00573 DocRect Rect; 00574 00575 BlendPath *pBlendPath = GetFirstBlendPath(); 00576 BlendPathOffset Offset; 00577 iterator ListPos = m_OffsetList.begin(); 00578 CCAttrMap *pAttrMap = NULL; 00579 while (pBlendPath != NULL) 00580 { 00581 DocRect PathRect; 00582 pAttrMap = pBlendPath->FindAppliedAttributes(); 00583 pBlendPath->m_pPath->GetTrueBoundingRect(&PathRect, 0, pAttrMap); 00584 if (ListPos != m_OffsetList.end() ) 00585 { 00586 Offset = *ListPos++; 00587 /* PathRect.hix += Offset.m_XOffset; 00588 PathRect.lox += Offset.m_XOffset; 00589 PathRect.hiy += Offset.m_YOffset; 00590 PathRect.loy += Offset.m_YOffset; 00591 */ 00592 } 00593 Rect = Rect.Union(PathRect); 00594 pAttrMap = NULL; 00595 pBlendPath = GetNextBlendPath(pBlendPath); 00596 } 00597 00598 return Rect; 00599 } 00600 00601 00602 /*********************************************************************************************** 00603 00604 > BOOL BrushRef::SetBitmapFillFlags() 00605 00606 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00607 Created: 7/12/99 00608 Inputs: 00609 Outputs: 00610 Returns: TRUE if we don't have a bitmap fill, or if we do and successfully made a copy 00611 Purpose: Because brush definitions exist independently of documents, but bitmap fills do not. 00612 Therefore if we make a brush with a bitmap fill and then delete them document we 00613 created it in we lose the fill. However the brush still exists, therefore this 00614 function searches for a bitmap fill attribute, and sets flags that tell the bitmap 00615 not to delete itself. 00616 NOTE: This means that we are responsible for deleting the bitmap fills that belong to us 00617 ***********************************************************************************************/ 00618 00619 BOOL BrushRef::SetBitmapFillFlags() 00620 { 00621 // for each blendpath we wish to find out if they have an applied bitmap fill attribute. 00622 // if so then we want to copy it, and replace it in the attribute map 00623 BlendPath* pBlendPath = GetFirstBlendPath(); 00624 00625 while (pBlendPath != NULL) 00626 { 00627 // there may be both a colour fill and transparency attribute, so get both 00628 AttrBitmapFill* pBMPFill = pBlendPath->GetAppliedBitmapColourFill(); 00629 if (pBMPFill != NULL) 00630 { 00631 // Get the attribute value 00632 BitmapFillAttribute* pVal = (BitmapFillAttribute*)pBMPFill->GetAttributeValue(); 00633 00634 if (pVal == NULL) 00635 { 00636 ERROR3("Couldn't retrieve attribute value"); 00637 return FALSE; 00638 } 00639 00640 KernelBitmap* pKBitmap = pVal->GetBitmap(); 00641 if (pKBitmap != NULL) 00642 { 00643 OILBitmap* pOBitmap = pKBitmap->GetActualBitmap(); 00644 00645 // tell the bitmaps that they are being used by us so that if the 00646 // document closes they don't get deleted 00647 if (pOBitmap != NULL) 00648 { 00649 pOBitmap->SetUsedByBrush(TRUE); 00650 pKBitmap->SetUsedByBrush(TRUE); 00651 } 00652 00653 } 00654 } 00655 00656 AttrBitmapFill* pTranspFill = pBlendPath->GetAppliedBitmapTranspFill(); 00657 if (pTranspFill != NULL) 00658 { 00659 // Get the attribute value 00660 BitmapFillAttribute* pVal = (BitmapFillAttribute*)pTranspFill->GetAttributeValue(); 00661 00662 if (pVal == NULL) 00663 { 00664 ERROR3("Couldn't retrieve attribute value"); 00665 return FALSE; 00666 } 00667 00668 KernelBitmap* pKBitmap = pVal->GetBitmap(); 00669 if (pKBitmap != NULL) 00670 { 00671 OILBitmap* pOBitmap = pKBitmap->GetActualBitmap(); 00672 00673 // tell the bitmaps that they are being used by us so that if the 00674 // document closes they don't get deleted 00675 if (pOBitmap != NULL) 00676 { 00677 pOBitmap->SetUsedByBrush(TRUE); 00678 pKBitmap->SetUsedByBrush(TRUE); 00679 } 00680 00681 } 00682 } 00683 00684 pBlendPath = GetNextBlendPath(pBlendPath); 00685 } 00686 return TRUE; 00687 } 00688 00689 00690 00691 /*********************************************************************************************** 00692 00693 > void BrushRef::DeleteBitmapFills() 00694 00695 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00696 Created: 7/12/99 00697 Inputs: 00698 Outputs: 00699 Returns: - 00700 Purpose: Searches for bitmap fill attributes and deletes their bitmaps, see previous function 00701 for the rationale. 00702 Note that this function was designed to be called by the BrushDefinition destructor. 00703 I cannot think of a good reason for wanting to use it anywhere else. 00704 ***********************************************************************************************/ 00705 00706 void BrushRef::DeleteBitmapFills() 00707 { 00708 // loop through each blendpath 00709 BlendPath* pBlendPath = GetFirstBlendPath(); 00710 00711 while (pBlendPath != NULL) 00712 { 00713 // retrieve the attribute node 00714 AttrBitmapFill* pBMPFill = pBlendPath->GetAppliedBitmapColourFill(); 00715 if (pBMPFill != NULL) 00716 { 00717 // get the attribute value 00718 BitmapFillAttribute* pVal = (BitmapFillAttribute*)pBMPFill->GetAttributeValue(); 00719 if (pVal != NULL) 00720 { 00721 // get the bitmap 00722 KernelBitmap* pBitmap = pVal->GetBitmap(); 00723 // if it has been flagged by us then zap it 00724 if (pBitmap != NULL && pBitmap->IsUsedByBrush()) 00725 { 00726 pBitmap->SetUsedByBrush(FALSE); 00727 pBitmap->Detach(); 00728 delete pBitmap; 00729 } 00730 } 00731 } 00732 pBlendPath = GetNextBlendPath(pBlendPath); 00733 } 00734 } 00735 00736 00737 00738 /*********************************************************************************************** 00739 00740 > void BrushRef::DeleteAttributesAndPath() 00741 00742 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00743 Created: 7/12/99 00744 Inputs: 00745 Outputs: 00746 Returns: - 00747 Purpose: Goes through all of the blendpaths and sets a flag which ensures that all the 00748 applied attributes of this blendpath are deleted upon destruction. This must not 00749 be used under normal circumstances because these attributes will still be in use 00750 by other objects. It was designed for when we are blending brush attributes and have 00751 to generate our attribute maps from scratch 00752 ***********************************************************************************************/ 00753 00754 void BrushRef::DeleteAttributesAndPath() 00755 { 00756 // BlendPath* pLastPath = NULL; 00757 BlendPath* pBlendPath = GetFirstBlendPath(); 00758 while (pBlendPath != NULL) 00759 { 00760 // ensures that all the applied attributes will be deleted when the object is deleted 00761 pBlendPath->DeleteAttributesAndPath(); 00762 pBlendPath = GetNextBlendPath(pBlendPath); 00763 00764 } 00765 } 00766 00767 00768 /*********************************************************************************************** 00769 00770 > void BrushRef::FreeAttributes() 00771 00772 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00773 Created: 7/12/99 00774 Inputs: 00775 Outputs: 00776 Returns: - 00777 Purpose: Goes through the blendpaths and asks them to delete their cached attribute map 00778 ***********************************************************************************************/ 00779 00780 void BrushRef::FreeAttributes() 00781 { 00782 // BlendPath* pLastPath = NULL; 00783 BlendPath* pBlendPath = GetFirstBlendPath(); 00784 while (pBlendPath != NULL) 00785 { 00786 pBlendPath->SetFreeAttributeFlag(TRUE); 00787 pBlendPath = GetNextBlendPath(pBlendPath); 00788 00789 } 00790 //DeleteBitmapFills(); // disabled until I get it working properly 00791 } 00792 00793 /*********************************************************************************************** 00794 00795 > void BrushRef::TranslateTo(DocCoord Destination) 00796 00797 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00798 Created: 7/12/99 00799 Inputs: Destination - the coord to translateto 00800 00801 Outputs: - 00802 Returns: - 00803 Purpose: Translates the blendpaths and their applied attributes to Destination 00804 ***********************************************************************************************/ 00805 00806 void BrushRef::TranslateTo(DocCoord Destination) 00807 { 00808 BlendPath* pBlendPath = GetFirstBlendPath(); 00809 CCAttrMap* pAttrMap = NULL; 00810 DocRect BRect; 00811 DocCoord CurrentCentre; 00812 Trans2DMatrix Trans; 00813 00814 while (pBlendPath != NULL) 00815 { 00816 // find out where we are 00817 BRect = pBlendPath->m_pPath->GetBoundingRect(); 00818 CurrentCentre = BRect.Centre(); 00819 00820 // set the translation in the matrix 00821 Trans.SetTransform(Destination.x - CurrentCentre.x, Destination.y - CurrentCentre.y); 00822 00823 // we want to transform attributes too 00824 pAttrMap = pBlendPath->FindAppliedAttributes(); 00825 if (pAttrMap == NULL) 00826 { 00827 ERROR3("No applied attributes"); 00828 } 00829 else 00830 { 00831 pAttrMap->Transform(Trans); 00832 pAttrMap = NULL; 00833 } 00834 pBlendPath->Transform(Trans); 00835 00836 pBlendPath = GetNextBlendPath(pBlendPath); 00837 } 00838 } 00839 00840 00841 /*********************************************************************************************** 00842 00843 > void BrushRef::TransformBitmapAttributes(TransformBase& Trans) 00844 00845 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00846 Created: 7/12/99 00847 Inputs: Trans - the transformation to perform 00848 00849 Outputs: - 00850 Returns: - 00851 Purpose: When a brush stroke is transformed in the document we do not really need to transform 00852 the blendpaths however we do need tot transform the attributes, otherwise bitmap 00853 fills become incorrect as do line widths etc. 00854 However if we transform all attributes then we also need to transform the blendpaths, 00855 because such things as radial fills are translated by the brush code from the position 00856 of the blendpaths. 00857 It is important however that we do not scale the blendpaths, as the scaling code 00858 assumes that they always stay the same size. 00859 ***********************************************************************************************/ 00860 00861 void BrushRef::TransformAttributes(TransformBase& Trans) 00862 { 00863 BlendPath *pBlendPath = GetFirstBlendPath(); 00864 CCAttrMap *pAttrMap = NULL; 00865 00866 CCRuntimeClass *pType; 00867 void *pVal; 00868 NodeAttribute *pNodeAttr; 00869 00870 while (pBlendPath != NULL) 00871 { 00872 // we want to transform attributes too 00873 pAttrMap = pBlendPath->FindAppliedAttributes(); 00874 if (pAttrMap == NULL) 00875 { 00876 ERROR3("No applied attributes"); 00877 } 00878 else 00879 { 00880 // monster bodge - currently we only actually want to transform line widths and bitmap fills 00881 for( CCAttrMap::iterator Pos = pAttrMap->GetStartPosition(); Pos != pAttrMap->GetEndPosition(); ) 00882 { 00883 // Get attr at position Pos 00884 pAttrMap->GetNextAssoc( Pos, pType, pVal ); 00885 00886 // pVal is actually an attribute, so get a ptr to it and render it 00887 pNodeAttr = (NodeAttribute *)pVal; 00888 00889 if (pNodeAttr->IsABitmapFill()) 00890 pNodeAttr->Transform(Trans); 00891 00892 if( pNodeAttr->IsALineWidthAttr() && FALSE != Trans.TransLines ) 00893 { 00894 INT32 Test = labs( INT32(Trans.GetScalar().MakeDouble() * ((AttrLineWidth*)pNodeAttr)->Value.LineWidth) ); 00895 if (Test >= 10) 00896 pNodeAttr->Transform(Trans); 00897 } 00898 00899 00900 } 00901 00902 pAttrMap = NULL; 00903 } 00904 00905 pBlendPath = GetNextBlendPath(pBlendPath); 00906 } 00907 return; 00908 } 00909 00910 /*--------------------------------------------------------------------------------------------- 00911 ----------------------------------------------------------------------------------------------- 00912 ------------------The BrushRefBlender Class---------------------------------------------------- 00913 ----------------------------------------------------------------------------------------------*/ 00914 00915 /*********************************************************************************************** 00916 00917 > BrushRefBlender::BrushRefBlender() 00918 00919 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00920 Created: 28/3/2000 00921 Inputs: - 00922 Outputs: - 00923 Returns: - 00924 Purpose: Default constructor. 00925 00926 ***********************************************************************************************/ 00927 00928 BrushRefBlender::BrushRefBlender() 00929 { 00930 m_pStartBrushRef = NULL; 00931 m_pEndBrushRef = NULL; 00932 00933 m_pTempCoords = NULL; 00934 m_pTempVerbs = NULL; 00935 m_pTempFlags = NULL; 00936 m_GBlendBuffSize = 0; 00937 m_pGBlendBuff = NULL; 00938 m_ArrayLength = 0; 00939 } 00940 00941 00942 /*********************************************************************************************** 00943 00944 > BrushRefBlender::~BrushRefBlender() 00945 00946 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00947 Created: 28/3/2000 00948 Inputs: - 00949 Outputs: - 00950 Returns: - 00951 Purpose: Default destructor. 00952 00953 ***********************************************************************************************/ 00954 00955 BrushRefBlender::~BrushRefBlender() 00956 { 00957 DeallocTempBuffers(); 00958 } 00959 00960 /*********************************************************************************************** 00961 00962 > void BrushRefBlender::SetBrushref(BrushRef* pBrushRef, BOOL Start) 00963 00964 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00965 Created: 28/3/2000 00966 Inputs: the brushref to set, and whether it is the first or last brushref 00967 Outputs: - 00968 Returns: - 00969 Purpose: Default destructor. 00970 00971 ***********************************************************************************************/ 00972 00973 void BrushRefBlender::SetBrushRef(BrushRef* pBrushRef, BOOL Start) 00974 { 00975 if (pBrushRef == NULL) 00976 return; 00977 if (Start) 00978 m_pStartBrushRef = pBrushRef; 00979 else 00980 m_pEndBrushRef = pBrushRef; 00981 } 00982 00983 00984 /*********************************************************************************************** 00985 00986 > BrushRef* BrushRefBlender::Blend(BrushRef* pStartBrush, BrushRef* pEndBrush, double Ratio) 00987 00988 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 00989 Created: 7/12/99 00990 Inputs: pStartBrush - the first brushref to blend 00991 pEndBrush - the other brushref to blend to 00992 Ratio - the ratio of that to this 00993 Outputs: 00994 Returns: a newly allocated brushref created by blending this with pOther 00995 Purpose: as above. A lot of this code is similar to that of NodeBlender::CreateBlends, however 00996 it is actuall used by the BrushComponent 00997 ***********************************************************************************************/ 00998 00999 BrushRef* BrushRefBlender::Blend(BrushRef* pStartBrush, BrushRef* pEndBrush, double Ratio) 01000 { 01001 if (pStartBrush == NULL || pEndBrush == NULL) 01002 { 01003 ERROR3("brush ref is NULL in BrushRef::Blend"); 01004 return NULL; 01005 } 01006 01007 if (Ratio < 0 || Ratio > 1) 01008 { 01009 ERROR3("Invalid blend ratio"); 01010 return NULL; 01011 } 01012 01013 // allocate the extra memory that we need 01014 if (!ReallocTempBuffers(1000)) 01015 return NULL; 01016 01017 // right, lets go to work. The first thing to do is translate both sets of paths to 0,0 01018 // the reason for this is that in the course of its normal existence the blendpaths can get 01019 // translated all over the place, so in order for our blend to make sense they should at least 01020 // be centered in the same place 01021 // We will also want to store their current location in order to translate them back when we're done 01022 // DocRect StartRect = pStartBrush->GetBoundingRect(); 01023 // DocRect EndRect = pEndBrush->GetBoundingRect(); 01024 // DocCoord StartCoord = StartRect.Centre(); 01025 // DocCoord EndCoord = EndRect.Centre(); 01026 01027 // pStartBrush->TranslateTo(DocCoord(0,0)); 01028 // pEndBrush->TranslateTo(DocCoord(0,0)); 01029 01030 01031 // Find num blend paths in start and end, and keep hold of the MAX value 01032 UINT32 NumPathsInStart = pStartBrush->GetNumBlendPaths(); 01033 UINT32 NumPathsInEnd = pEndBrush->GetNumBlendPaths(); 01034 UINT32 MaxNumPaths = max(NumPathsInStart,NumPathsInEnd); 01035 01036 if (NumPathsInStart == 0 || NumPathsInEnd == 0) 01037 return NULL; 01038 01039 // This object is used to step along the the two lists of objects choosing a pair to go and blend. 01040 // It mainly comes into play when there are different numbers of objects in the two lists. 01041 ListStepper Stepper; 01042 Stepper.Init(NumPathsInStart, NumPathsInEnd, 0); 01043 INT32 NextPathStart, NextPathEnd; 01044 01045 //allocate our new brushref 01046 BrushRef* pBlendedBrushRef = new BrushRef; 01047 if (pBlendedBrushRef == NULL) 01048 return NULL; 01049 01050 // set up our variables, they will be allocated in the loop (slow I know) 01051 Path* pBlendedPath = NULL; 01052 BlendPath* pNewBlendPath = NULL; 01053 CCAttrMap* pBlendedAttrMap = NULL; 01054 01055 // Get the first pair of objects to blend 01056 Stepper.GetNext(&NextPathStart,&NextPathEnd); 01057 01058 // The first pair of blend paths become the current blend path pair 01059 // Get ptrs to these, plus the subpath IDs of these 01060 BlendPath* pCurrBlendPathStart = pStartBrush->GetBlendPath(NextPathStart); 01061 BlendPath* pCurrBlendPathEnd = pEndBrush->GetBlendPath(NextPathEnd ); 01062 UINT32 CurrSubPathIDStart = pCurrBlendPathStart->GetSubPathID(); 01063 UINT32 CurrSubPathIDEnd = pCurrBlendPathEnd ->GetSubPathID(); 01064 01065 // We also need info on the next blend path pair, so get some vars ready 01066 BlendPath* pNextBlendPathStart = NULL; 01067 BlendPath* pNextBlendPathEnd = NULL; 01068 UINT32 NextSubPathIDStart = CurrSubPathIDStart; // This was uninitialized - AMB guessed a good value 01069 UINT32 NextSubPathIDEnd = CurrSubPathIDEnd; // This was uninitialized - AMB guessed a good value 01070 01071 for (UINT32 NextPath = 0; NextPath < MaxNumPaths; NextPath++) 01072 { 01073 // allocate the variables 01074 pBlendedPath = new Path; 01075 pBlendedAttrMap = new CCAttrMap(30); 01076 01077 if (pBlendedPath == NULL || pBlendedAttrMap == NULL ) 01078 goto ExitNull; 01079 if (!pBlendedPath->Initialise()) 01080 goto ExitNull; 01081 01082 // Get the next pair of objects to blend 01083 Stepper.GetNext(&NextPathStart,&NextPathEnd); 01084 01085 // if we haven't run out then assign the next path variables 01086 if (NextPathStart >= 0 && NextPathEnd >= 0) 01087 { 01088 pNextBlendPathStart = pStartBrush->GetBlendPath(NextPathStart); 01089 pNextBlendPathEnd = pEndBrush->GetBlendPath(NextPathEnd); 01090 NextSubPathIDStart = pNextBlendPathStart->GetSubPathID(); 01091 NextSubPathIDEnd = pNextBlendPathEnd->GetSubPathID(); 01092 } 01093 01094 01095 if (BlendAttributes(pCurrBlendPathStart, pCurrBlendPathEnd, pBlendedAttrMap, Ratio)) 01096 { 01097 // Blend the paths together, putting the blended path in BlendedPath 01098 if (BlendPaths(pCurrBlendPathStart,pCurrBlendPathEnd,Ratio)) 01099 { 01100 // The blended path will be filled if either of the paths are filled 01101 // The blended path will be stroked if either of the paths are stroked 01102 BOOL Filled = pCurrBlendPathStart->IsFilled() || pCurrBlendPathEnd->IsFilled(); 01103 BOOL Stroked = pCurrBlendPathStart->IsStroked() || pCurrBlendPathEnd->IsStroked(); 01104 01105 if (!pBlendedPath->MakeSpaceInPath(m_ArrayLength)) 01106 goto ExitNull; 01107 pBlendedPath->MergeTwoPaths(m_pTempCoords,m_pTempVerbs,m_pTempFlags,m_ArrayLength,Filled); 01108 pBlendedPath->IsFilled = Filled; 01109 pBlendedPath->IsStroked = Stroked; 01110 01111 // We haven't yet got a complete path to render or pass back if next path has the same ID and is 01112 // a different path 01113 // (this applies to the start OR the end path) 01114 BOOL NotACompletePath = ((CurrSubPathIDStart == NextSubPathIDStart && pCurrBlendPathStart != pNextBlendPathStart) || 01115 (CurrSubPathIDEnd == NextSubPathIDEnd && pCurrBlendPathEnd != pNextBlendPathEnd )); 01116 01117 if (!NotACompletePath) 01118 { 01119 // it all worked, lets allocate a new blendpath 01120 pNewBlendPath = new BlendPath; 01121 if (pNewBlendPath == NULL) 01122 goto ExitNull; 01123 01124 // tell it to use our blended path and attributes 01125 pNewBlendPath->SetPath(pBlendedPath); 01126 pNewBlendPath->SetAppliedAttributes(pBlendedAttrMap); 01127 01128 // give it to the brushref 01129 pBlendedBrushRef->AddBlendPath(pNewBlendPath); 01130 } 01131 else 01132 goto ExitNull; 01133 01134 pNewBlendPath = NULL; 01135 pBlendedPath = NULL; 01136 pBlendedAttrMap = NULL; 01137 } 01138 else // end if blendpaths 01139 goto ExitNull; 01140 } // end if blendattributes 01141 else 01142 goto ExitNull; 01143 } // end for 01144 01145 // DeallocTempBuffers(); 01146 01147 // translate the brushes back 01148 //pStartBrush->TranslateTo(StartCoord); 01149 //pEndBrush->TranslateTo(EndCoord); 01150 return pBlendedBrushRef; 01151 01152 // just so I don't have to keep repeating this code, if an allocation fails then come here where everything is deleted 01153 ExitNull: 01154 if (pBlendedPath != NULL) 01155 delete pBlendedPath; 01156 if (pBlendedBrushRef != NULL) 01157 delete pBlendedBrushRef; 01158 if (pBlendedAttrMap != NULL) 01159 delete pBlendedAttrMap; 01160 if (pNewBlendPath != NULL) 01161 delete pNewBlendPath; 01162 ERROR3("Something went wrong in BrushRefBlender::Blend"); 01163 return NULL; 01164 } 01165 01166 01167 01168 /******************************************************************************************** 01169 01170 > DocCoord* BrushRefBlender::GetCoordArray(UINT32 MinSize); 01171 01172 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01173 Created: 7/11/94 01174 Inputs: MinSize = min size the array should be 01175 Outputs: - 01176 Returns: Ptr to the array, or NULL if can't get memory 01177 Purpose: Used to get an array you can write to. 01178 SeeAlso: - 01179 01180 ********************************************************************************************/ 01181 01182 DocCoord* BrushRefBlender::GetCoordArray(UINT32 MinSize) 01183 { 01184 MinSize++; 01185 if (m_TempArraySize >= MinSize) return m_pTempCoords; 01186 01187 if (ReallocTempBuffers(MinSize)) 01188 return m_pTempCoords; 01189 else 01190 return NULL; 01191 } 01192 01193 /******************************************************************************************** 01194 01195 > PathVerb* BrushRefBlender::GetVerbArray(UINT32 MinSize); 01196 01197 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01198 Created: 7/11/94 01199 Inputs: MinSize = min size the array should be 01200 Outputs: - 01201 Returns: Ptr to the array, or NULL if can't get memory 01202 Purpose: Used to get an array you can write to. 01203 SeeAlso: - 01204 01205 ********************************************************************************************/ 01206 01207 PathVerb* BrushRefBlender::GetVerbArray(UINT32 MinSize) 01208 { 01209 MinSize++; 01210 if (m_TempArraySize >= MinSize) return m_pTempVerbs; 01211 01212 if (ReallocTempBuffers(MinSize)) 01213 return m_pTempVerbs; 01214 else 01215 return NULL; 01216 } 01217 01218 /******************************************************************************************** 01219 01220 > PathFlags* BrushRefBlender::GetFlagArray(UINT32 MinSize); 01221 01222 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01223 Created: 7/11/94 01224 Inputs: MinSize = min size the array should be 01225 Outputs: - 01226 Returns: Ptr to the array, or NULL if can't get memory 01227 Purpose: Used to get an array you can write to. 01228 SeeAlso: - 01229 01230 ********************************************************************************************/ 01231 01232 PathFlags* BrushRefBlender::GetFlagArray(UINT32 MinSize) 01233 { 01234 MinSize++; 01235 if (m_TempArraySize >= MinSize) return m_pTempFlags; 01236 01237 if (ReallocTempBuffers(MinSize)) 01238 return m_pTempFlags; 01239 else 01240 return NULL; 01241 } 01242 01243 /******************************************************************************************** 01244 01245 > UINT32* BrushRefBlender::GetGBlendBuff(UINT32 MinSize); 01246 01247 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01248 Created: 7/11/94 01249 Inputs: MinSize = min size the buffer should be 01250 Outputs: - 01251 Returns: Ptr to the buffer, or NULL if can't get memory 01252 Purpose: Used to get a buffer you can write to. 01253 SeeAlso: - 01254 01255 ********************************************************************************************/ 01256 01257 UINT32* BrushRefBlender::GetGBlendBuff(UINT32 MinSize) 01258 { 01259 MinSize++; 01260 if (m_GBlendBuffSize >= MinSize) return m_pGBlendBuff; 01261 01262 if (m_pGBlendBuff != NULL) CCFree(m_pGBlendBuff); 01263 01264 m_pGBlendBuff = (UINT32*) CCMalloc(MinSize*sizeof(UINT32)); 01265 01266 if (m_pGBlendBuff != NULL) 01267 m_GBlendBuffSize = MinSize; 01268 else 01269 m_GBlendBuffSize = 0; 01270 01271 return m_pGBlendBuff; 01272 } 01273 01274 01275 /******************************************************************************************** 01276 01277 > BOOL BrushRefBlender::ReallocTempBuffers(UINT32 Size) 01278 01279 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01280 Created: 28/3/2000 01281 Inputs: Size = Size the temp arrays should be 01282 Outputs: - 01283 Returns: - 01284 Purpose: Allocates memory for the temp path arrays, and sets the size var to 0 01285 You can use calls to GetCoordArray(), GetVerbArray() and GetFlagArray() to get the alloced arrays. 01286 SeeAlso: - 01287 01288 ********************************************************************************************/ 01289 01290 BOOL BrushRefBlender::ReallocTempBuffers(UINT32 Size) 01291 { 01292 DeallocTempBuffers(); 01293 01294 // Allocate the arrays 01295 m_TempArraySize = Size; 01296 m_pTempCoords = (DocCoord*) CCMalloc(Size*sizeof(DocCoord)); 01297 m_pTempVerbs = (PathVerb*) CCMalloc(Size*sizeof(PathVerb)); 01298 m_pTempFlags = (PathFlags*) CCMalloc(Size*sizeof(PathFlags)); 01299 01300 // If any of the arrays are not allocated, dealloc the alloced ones, and return FALSE 01301 if (m_pTempCoords == NULL || m_pTempVerbs == NULL || m_pTempFlags == NULL) 01302 { 01303 DeallocTempBuffers(); 01304 return FALSE; 01305 } 01306 01307 // It's all OK, so return TRUE 01308 return TRUE; 01309 } 01310 01311 /******************************************************************************************** 01312 01313 > void BrushRefBlender::DeallocTempBuffers() 01314 01315 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01316 Created: 28/3/2000 01317 Inputs: - 01318 Outputs: - 01319 Returns: - 01320 Purpose: Releases memory allocated for the temp path arrays, and sets the size var to 0 01321 SeeAlso: - 01322 01323 ********************************************************************************************/ 01324 01325 void BrushRefBlender::DeallocTempBuffers() 01326 { 01327 if (m_pTempCoords != NULL) { CCFree(m_pTempCoords); m_pTempCoords = NULL; } 01328 if (m_pTempVerbs != NULL) { CCFree(m_pTempVerbs); m_pTempVerbs = NULL; } 01329 if (m_pTempFlags != NULL) { CCFree(m_pTempFlags); m_pTempFlags = NULL; } 01330 m_TempArraySize = 0; 01331 01332 if (m_pGBlendBuff != NULL) { CCFree(m_pGBlendBuff); m_pGBlendBuff = NULL; } 01333 m_GBlendBuffSize = 0; 01334 } 01335 01336 01337 /******************************************************************************************** 01338 01339 > BOOL BrushRefBlender::BlendAttributes(BlendPath* pBlendPathStart, BlendPath* pBlendPathEnd, 01340 CCAttrMap* pBlendedAttrMap,double BlendRatio) 01341 01342 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01343 Created: 27/3/2000 01344 Inputs: 01345 pBlendPathStart = ptr to blend path to blend from 01346 pBlendPathEnd = ptr to blend path to blend to 01347 pBlendedAttrMap = ptr to map to store the blended attributes in 01348 BlendRatio = amount to blend by (0.0 <= BlendPath <= 1.0) 01349 Outputs: - 01350 Returns: TRUE if successful, FALSE otherwise 01351 Purpose: Blends the attributes of the two BlendPath objects by the amount specified in BlendRatio 01352 This is pretty much the same as the fn. by the same name in NodeBlender 01353 SeeAlso: - 01354 01355 ********************************************************************************************/ 01356 01357 BOOL BrushRefBlender::BlendAttributes( BlendPath* pBlendPathStart, BlendPath* pBlendPathEnd, 01358 CCAttrMap* pBlendedAttrMap,double BlendRatio) 01359 { 01360 // Check entry params 01361 BOOL ok = (pBlendPathStart != NULL && 01362 pBlendPathEnd != NULL && pBlendedAttrMap != NULL); 01363 ERROR3IF(!ok,"One or more NULL entry params"); 01364 if (!ok) return FALSE; 01365 01366 // Find the attributes that are applied to the blend paths 01367 CCAttrMap* pAttrMapStart = pBlendPathStart->FindAppliedAttributes(); 01368 CCAttrMap* pAttrMapEnd = pBlendPathEnd->FindAppliedAttributes(); 01369 01370 // If either are NULL, return FALSE 01371 if (pAttrMapStart == NULL || pAttrMapEnd == NULL) return FALSE; 01372 01373 // These vars are used as params to the CCAttrMap funcs 01374 CCRuntimeClass *pTypeStart; 01375 void *pValStart; 01376 void *pValEnd; 01377 double OldBlendRatio = BlendRatio; 01378 // Process each attribute in turn 01379 CCAttrMap::iterator PosStart = pAttrMapStart->GetStartPosition(); 01380 for (;PosStart != pAttrMapStart->GetEndPosition();) 01381 { 01382 // Get a ptr to the attr at position PosStart in the start node's attr map 01383 pAttrMapStart->GetNextAssoc( PosStart, pTypeStart, pValStart ); 01384 NodeAttribute* pNodeAttrStart = (NodeAttribute *)pValStart; 01385 01386 BlendRatio = OldBlendRatio; 01387 // Diccon 10/99 When using non-linear profiles for the objects those attributes 01388 // that make use of control points were not being profiled, making the objects look strange. 01389 // to avoid this those attributes now share the same profiles as the objects. 01390 /* if (pNodeAttrStart->IsAGradFill()) 01391 { 01392 01393 if (!((AttrFillGeometry*)pNodeAttrStart)->IsAColourFill()) 01394 { 01395 01396 BlendRatio = GetObjectRatio(); 01397 01398 } 01399 else 01400 { 01401 BlendRatio = GetInvertedAttributeRatio(); 01402 01403 } 01404 01405 } 01406 if (pNodeAttrStart->IsAFlatFill() || (pNodeAttrStart->GetRuntimeClass() == CC_RUNTIME_CLASS(AttrLineWidth))) 01407 { 01408 BlendRatio = GetInvertedAttributeRatio(); 01409 } 01410 01411 */ 01412 // Get a blended attribute 01413 NodeAttribute* pBlendedNodeAttr = NULL; 01414 01415 // Find an attr of the same type in the end object's attr list, 01416 // and blend the two attrs together 01417 if( pAttrMapEnd->Lookup( pTypeStart, pValEnd ) ) 01418 { 01419 // We've found a matching end attr, so try to blend it with the start attr 01420 01421 // Set up the param object to pass to the start attr's blend method 01422 BlendAttrParam BlendParam; 01423 01424 // Initialise the BlendParam with the end attr and blend ratio 01425 if (BlendParam.Init(NULL, 01426 (NodeAttribute *)pValEnd,BlendRatio,COLOURBLEND_FADE, 01427 pAttrMapStart, pAttrMapEnd)) 01428 { 01429 // Successfully initialised, so now try blending the attributes 01430 if (pNodeAttrStart->Blend(&BlendParam)) 01431 { 01432 // Attrs successfully blended, now get a ptr to the new attr. 01433 // Once we get the blended attr ptr, it belongs to us, so we have 01434 // to delete it when it is not needed 01435 pBlendedNodeAttr = BlendParam.GetBlendedAttr(); 01436 } 01437 } 01438 } 01439 01440 // If we have a blended attr, pBlendedNodeAttr != NULL 01441 if (pBlendedNodeAttr != NULL) 01442 { 01443 // Get the type of the blended attr 01444 CCRuntimeClass *pTypeBlend = pBlendedNodeAttr->GetAttributeType(); 01445 void *pValBlend; 01446 01447 // If we already have an attr in the blended attr map of the same type, 01448 // remove it and delete it, before inserting a new attr of this type 01449 if (pBlendedAttrMap->Lookup(pTypeBlend,pValBlend)) 01450 { 01451 if (pValBlend != NULL) 01452 { 01453 pBlendedAttrMap->RemoveKey(pTypeBlend); 01454 delete (NodeAttribute*)pValBlend; 01455 } 01456 } 01457 // add it to the blend map 01458 pBlendedAttrMap->SetAt( pTypeBlend, pBlendedNodeAttr ); 01459 } 01460 } 01461 01462 01463 return TRUE; 01464 } 01465 01466 01467 /******************************************************************************************** 01468 01469 > BOOL BrushRefBlender::BlendPaths(BlendPath* pBlendPathStart,BlendPath* pBlendPathEnd,double BlendRatio) 01470 01471 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01472 Created: 27/3/2000 01473 Inputs: pBlendPathStart = ptr to blend path to blend from 01474 pBlendPathEnd = ptr to blend path to blend to 01475 BlendRatio = amount to blend by (0.0 <= BlendPath <= 1.0) 01476 Outputs: The blended path is stored in three arrays: the coords, the verbs, and the flags. 01477 The arrays are: 01478 01479 pTempCoords 01480 pTempVerbs 01481 pTempFlags 01482 01483 ArrayLength = the length of all three arrays 01484 01485 This allows the caller to decide what to do with the blended path in a very flexible way. 01486 01487 Returns: TRUE if successful, FALSE otherwise 01488 Purpose: Blends two BlendPath objects by the amount specified in BlendRatio 01489 This is pretty much the same as the fn. by the same name in NodeBlender 01490 SeeAlso: 01491 01492 ********************************************************************************************/ 01493 01494 BOOL BrushRefBlender::BlendPaths(BlendPath* pBlendPathStart,BlendPath* pBlendPathEnd,double BlendRatio) 01495 { 01496 // Check entry params 01497 BOOL ok = (pBlendPathStart != NULL && pBlendPathEnd != NULL); 01498 if (ok) ok = (pBlendPathStart->GetBlendNode() != NULL && pBlendPathEnd->GetBlendNode() != NULL); 01499 ERROR3IF(!ok,"One or more NULL entry params"); 01500 if (!ok) return FALSE; 01501 01502 // Get the types of the two paths 01503 PathTypeEnum PathTypeStart = pBlendPathStart->GetPathType(); 01504 PathTypeEnum PathTypeEnd = pBlendPathEnd ->GetPathType(); 01505 01506 // The blended path will be closed if either of the paths is a shape 01507 BOOL Closed = (PathTypeStart == PATHTYPE_SHAPE) || (PathTypeEnd == PATHTYPE_SHAPE); 01508 01509 Path * pPathStart = NULL; 01510 01511 // Find the paths associated with the start and end blend paths 01512 if (pBlendPathStart->GetBlendNode()->IsNodePath()) 01513 { 01514 pPathStart = &(((NodePath *)pBlendPathStart->GetBlendNode())->InkPath); 01515 } 01516 else 01517 { 01518 pPathStart = &(((NodePath *)((NodeCompound *)pBlendPathStart->GetBlendNode())->GetNodeToBlend())->InkPath); 01519 } 01520 01521 Path * pPathEnd = NULL; 01522 01523 if (pBlendPathEnd->GetBlendNode()->IsNodePath()) 01524 { 01525 pPathEnd = &(((NodePath *)pBlendPathEnd->GetBlendNode())->InkPath); 01526 } 01527 else 01528 { 01529 pPathEnd = &(((NodePath *)((NodeCompound *)pBlendPathEnd->GetBlendNode())->GetNodeToBlend())->InkPath); 01530 } 01531 01532 // Calculate how large the arrays have to be to store the blended path definition 01533 INT32 DestPathSize = ((pPathStart->GetNumCoords()+pPathEnd->GetNumCoords())*3)+500; 01534 01535 // Get some arrays used to hold the blended path data, and error if any are NULL 01536 DocCoord* pDestCoords = GetCoordArray(DestPathSize); 01537 PathVerb* pDestVerbs = GetVerbArray(DestPathSize); 01538 PathFlags* pDestFlags = GetFlagArray(DestPathSize); 01539 UINT32* pBuff = GetGBlendBuff(DestPathSize); 01540 if (pDestCoords == NULL || pDestVerbs == NULL || pDestFlags == NULL || pBuff == NULL) 01541 return FALSE; 01542 01543 // This section copes with the case when blending a line with a shape. 01544 // In this case we need to get a temp path the is actually a shape version of the line. 01545 // The line is simply reversed back onto itself to form a shape that would look identical to the 01546 // line if rendered. This allows the line to appear to open up to the shape when blended. 01547 Path Shape; 01548 if (PathTypeStart != PathTypeEnd) 01549 { 01550 BOOL ok = FALSE; 01551 if (!Shape.Initialise()) return FALSE; 01552 01553 // if going from a line to a shape, convert the start path to a shape 01554 if (PathTypeStart == PATHTYPE_LINE && PathTypeEnd == PATHTYPE_SHAPE) 01555 { 01556 ok = NodeBlender::ConvertLineToShape(pPathStart,&Shape); 01557 pPathStart = &Shape; 01558 } 01559 01560 // if going from a shape to a line, convert the end path to a shape 01561 if (PathTypeStart == PATHTYPE_SHAPE && PathTypeEnd == PATHTYPE_LINE) 01562 { 01563 ok = NodeBlender::ConvertLineToShape(pPathEnd,&Shape); 01564 pPathEnd = &Shape; 01565 } 01566 01567 if (!ok) return FALSE; 01568 } 01569 01570 BOOL OneToOne = FALSE; 01571 // Now actually blend the two paths 01572 01573 GBlend GBlendObj; 01574 01575 // Define the blend 01576 GBlendObj.Define( (PPOINT)pPathStart->GetCoordArray(), // Specify the start path 01577 pPathStart->GetVerbArray(), 01578 pPathStart->GetNumCoords(), 01579 01580 (PPOINT)pPathEnd ->GetCoordArray(), // Specify the end path 01581 pPathEnd ->GetVerbArray(), 01582 pPathEnd ->GetNumCoords(), 01583 01584 OneToOne, // The one-to-one flag 01585 FLATNESS, // Flatness 01586 01587 pBuff, // Buffer for GBlend to use 01588 DestPathSize*sizeof(UINT32)); // The buffer size 01589 01590 // Blend the paths 01591 m_ArrayLength = GBlendObj.Blend(BlendRatio, // The blend ratio, 0.0 < BlendRatio < 1.0 01592 (PPOINT)pDestCoords, // Array to store blended coords 01593 pDestVerbs, // Array to store blended verbs 01594 DestPathSize); // The num elements in the two arrays 01595 01596 01597 // If we're blending a line to another line, we need to make sure that the blended line 01598 // is going in a direction that corresponds to the source lines. This ensures attributes 01599 // that depend on this direction (e.g. start and end arrows) look correct. 01600 // 01601 // When creating blend paths of lines, we can detect if the blend path has been reversed, 01602 // in relation to the original path, by the original mapping value. 01603 // If it's 0 it has NOT been reversed, otherwise it's been reversed. 01604 // 01605 // If the blend ratio is <=0.5, the blended path is closest to the start blend path, 01606 // so we look at the start blend path's original mapping. 01607 // 01608 // If blend ration > 0.5, look at the end blend path's original mapping. 01609 // 01610 // The (BlendRation <= 0.5) cut-off point is the same as the cut-off point used in the blending 01611 // of attributes. 01612 if (pBlendPathStart->IsLine() && pBlendPathEnd->IsLine()) 01613 { 01614 BlendPath* pBlendPath; 01615 if (BlendRatio <= 0.5) 01616 pBlendPath = pBlendPathStart; 01617 else 01618 pBlendPath = pBlendPathEnd; 01619 01620 if (pBlendPath->GetOrigMapping() != 0) 01621 NodeBlender::ReversePath(pDestCoords,pDestVerbs,m_ArrayLength); 01622 } 01623 01624 // We need to do some work on the blended path 01625 if (!NodeBlender::ProcessBlendedPath(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Closed)) 01626 return FALSE; 01627 01628 return TRUE; 01629 } 01630 01631