#include <ppvecstr.h>
Inheritance diagram for PathProcessorStrokeVector:
Public Member Functions | |
PathProcessorStrokeVector () | |
virtual void | ProcessPath (Path *pPath, RenderRegion *pRender, PathShape ShapePath=PATHSHAPE_PATH) |
Called by the RenderRegion to apply the path processing operation to the given path. | |
virtual BOOL | WillChangeFillAndStrokeSeparately (void) |
Called by the RenderRegion to determine if this PathProcessorStrokeVector affects the "fill" and "stroke" portions of the path separately. (Generally speaking, only fill/stroke providers will cause these two different "bits" of a path to be rendered separately). This call is made BEFORE this Processor's ProcessPath function will be called. | |
virtual BOOL | NeedsTransparency () const |
Determine if this stroke type needs transparency in order to render. Vector strokes. | |
virtual BOOL | IsDifferent (PathProcessorStroke *pOther) |
Equality operator. | |
virtual PathProcessorStroke * | Clone (void) |
To copy PathProcessorStroke or derived-class object. | |
virtual BOOL | AllowsPropertiesDialog (void) |
void | SetStrokeDefinition (StrokeHandle Handle) |
Sets this path processor up to use the given vector stroke definition in all future rendering. | |
StrokeHandle | GetStrokeDefinition (void) const |
Private Member Functions | |
CC_DECLARE_DYNAMIC (PathProcessorStrokeVector) | |
Private Attributes | |
StrokeHandle | StrokeID |
Friends | |
class | RenderRegion |
This can be used to "filter" almost any rendering, but is mainly intended for use by stroke and fill providers, which replace input paths with more suitable shapes to be rendered.
Notes: This processor is set up with a vector clipart "group" which it "moulds" along each stroke it renders in ProcessPath.
Definition at line 134 of file ppvecstr.h.
|
Definition at line 140 of file ppvecstr.h. 00140 { StrokeID = StrokeHandle_NoStroke; };
|
|
Reimplemented from PathProcessor. Definition at line 150 of file ppvecstr.h. 00150 {return TRUE;}
|
|
|
|
To copy PathProcessorStroke or derived-class object.
Reimplemented from PathProcessorStroke. Definition at line 630 of file ppvecstr.cpp. 00631 { 00632 // Clone this object - this can be done by just creating a new one 00633 PathProcessorStrokeVector *pClone = new PathProcessorStrokeVector; 00634 00635 // And copy the (base class) parent-attribute pointer so we know when our 00636 // parent attribute is "current" in the render region. 00637 if (pClone != NULL) 00638 { 00639 pClone->SetParentAttr(GetParentAttr()); 00640 pClone->StrokeID = StrokeID; 00641 } 00642 00643 return(pClone); 00644 }
|
|
Definition at line 154 of file ppvecstr.h. 00154 { return(StrokeID); };
|
|
Equality operator.
Reimplemented from PathProcessorStroke. Definition at line 603 of file ppvecstr.cpp. 00604 { 00605 ERROR3IF(pOther == NULL, "Illegal NULL param"); 00606 00607 if (GetRuntimeClass() != pOther->GetRuntimeClass()) 00608 return(TRUE); 00609 00610 // We're different if we use different stroke definitions 00611 return(StrokeID != ((PathProcessorStrokeVector *)pOther)->StrokeID); 00612 }
|
|
Determine if this stroke type needs transparency in order to render. Vector strokes.
Reimplemented from PathProcessorStroke. Definition at line 225 of file ppvecstr.cpp. 00226 { 00227 StrokeDefinition *pStrokeDef = StrokeComponent::FindStroke(StrokeID); 00228 if (pStrokeDef == NULL) 00229 { 00230 return(FALSE); 00231 } 00232 00233 return(pStrokeDef->NeedsTransparency()); 00234 }
|
|
Called by the RenderRegion to apply the path processing operation to the given path.
Notes: * When rendering a path, always pass in your 'this' pointer to RenderRegion::DrawPath, so that you don't start an infinite recursion! To stop rendering of the path, simply return without calling the RR To render this path unchanged, simply call directly back to the RR: pRender->DrawPath(pPath, this); Only affect the fill of this path if pPath->IsFilled Only affect the stroke of this path if pPath->IsStroked If converting a path into a "filled path" for stroking, the output path should be rendered with IsStroked=FALSE or it'll get a line around the outside! Reimplemented from PathProcessorStroke. Definition at line 273 of file ppvecstr.cpp. 00276 { 00277 PORTNOTETRACE("other","PathProcessorStrokeVector::ProcessPath - do nothing"); 00278 #ifndef EXCLUDE_FROM_XARALX 00279 ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params"); 00280 00281 // Get the RenderRegion SubRenderContext and see if we're returning part-way through a background render 00282 VectorStrokeSubRenderContext *pSubRenderContext = (VectorStrokeSubRenderContext *)pRender->GetSubRenderState(); 00283 if (pSubRenderContext != NULL && !IS_A(pSubRenderContext, VectorStrokeSubRenderContext)) 00284 { 00285 // We can't use the sub render context, because it's not ours! 00286 pSubRenderContext = NULL; 00287 } 00288 00289 // --- If we don't have a valid stroke definition, then get the base class to render 00290 // the stroke as a simple flat-filled stroke. 00291 StrokeDefinition *pStrokeDef = StrokeComponent::FindStroke(StrokeID); 00292 if (pStrokeDef == NULL) 00293 { 00294 PathProcessorStroke::ProcessPath(pPath, pRender); 00295 return; 00296 } 00297 00298 // --- See if we have to create a new SubRenderContext, or if we can use the one passed in. 00299 // We always store all relevant variables in a SubRenderContext object so that we can easily 00300 // return control to the RenderRegion without having to copy lots of local values in/out. 00301 const BOOL CreateSubRenderContext = (pSubRenderContext == NULL); 00302 if (CreateSubRenderContext) 00303 { 00304 pSubRenderContext = new VectorStrokeSubRenderContext; 00305 if (pSubRenderContext == NULL) 00306 { 00307 pRender->DrawPath(pPath, this, ShapePath); 00308 return; 00309 } 00310 00311 // --- If the provided path is not stroked, then we'll just pass it straight through 00312 // We also don't touch it if we're doing EOR rendering, or click hit detection 00313 if (!pPath->IsStroked || pRender->DrawingMode != DM_COPYPEN || pRender->IsHitDetect()) 00314 { 00315 delete pSubRenderContext; 00316 pRender->DrawPath(pPath, this, ShapePath); 00317 return; 00318 } 00319 00320 // --- If the quality is set low, or if the current stroke attribute is not our "parent" 00321 // attribute (so we're not the "current" stroker) then strokes are just rendered as centrelines 00322 // BLOCK 00323 { 00324 QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY); 00325 StrokeTypeAttrValue *pTypeAttr = (StrokeTypeAttrValue *) pRender->GetCurrentAttribute(ATTR_STROKETYPE); 00326 00327 if ((pQuality != NULL && pQuality->QualityValue.GetLineQuality() != Quality::FullLine) || 00328 (pTypeAttr != NULL && pTypeAttr != GetParentAttr())) 00329 { 00330 delete pSubRenderContext; 00331 pRender->DrawPath(pPath, this, ShapePath); 00332 return; 00333 } 00334 } 00335 00336 // --- We don't expect the input path to be stroked AND filled on entry 00337 ERROR3IF(pPath->IsFilled, "PathProcessor expected RenderRegion to handle IsFilled case"); 00338 00339 // --- Get the current line width & Join Style from the render region 00340 // BLOCK 00341 { 00342 LineWidthAttribute *pWidthAttr = (LineWidthAttribute *) pRender->GetCurrentAttribute(ATTR_LINEWIDTH); 00343 if (pWidthAttr != NULL) 00344 pSubRenderContext->LineWidth = pWidthAttr->LineWidth; 00345 00346 JoinTypeAttribute *pJoinAttr = (JoinTypeAttribute *) pRender->GetCurrentAttribute(ATTR_JOINTYPE); 00347 if (pJoinAttr != NULL) 00348 pSubRenderContext->JoinStyle = pJoinAttr->JoinType; 00349 } 00350 } 00351 00352 // --- Create a new path to be rendered in place of the provided path 00353 // Note that I use a large allocation size so that reallocation need not be done 00354 // frequently, which also helps reduce memory fragmentation. 00355 Path *pOutput = new Path; 00356 if (pOutput == NULL) 00357 { 00358 if (!pRender->IsSubRenderStateLocked()) 00359 pRender->SetSubRenderState(NULL); 00360 delete pSubRenderContext; 00361 pRender->DrawPath(pPath, this, ShapePath); 00362 return; 00363 } 00364 00365 pOutput->Initialise(128, 128); 00366 00367 00368 // --- Find our Variable Width function 00369 if (CreateSubRenderContext) 00370 { 00371 // --- Get the variable line width descriptor from the render region 00372 VariableWidthAttrValue *pVarWidthAttr = (VariableWidthAttrValue *) pRender->GetCurrentAttribute(ATTR_VARWIDTH); 00373 if (pVarWidthAttr != NULL) 00374 pSubRenderContext->pValFunc = pVarWidthAttr->GetWidthFunction(); 00375 } 00376 00377 ValueFunction *pValFunc = pSubRenderContext->pValFunc; 00378 00379 // If we couldn't find a proper value function, then we'll default to constant-width. 00380 // We keep a static Constant function around always, because it's thread-safe and because 00381 // that saves us the overhead of creating and deleting it on the stack each time we're called 00382 static ValueFunctionConstant Constant(1.0); 00383 if (pValFunc == NULL) 00384 pValFunc = &Constant; 00385 00386 00387 // --- Find our brush clipart tree 00388 Node *pBrush = pStrokeDef->GetStrokeTree(); 00389 ERROR3IF(!IS_A(pBrush, Spread), "Brush does not start with a Spread Node!"); 00390 DocRect BrushBounds = ((Spread *)pBrush)->GetBoundingRect(); 00391 00392 // Get a PathStroker to map paths onto the destination stroke with 00393 PathStrokerVector Stroker(pValFunc, pSubRenderContext->LineWidth, 00394 LineCapButt, &BrushBounds); 00395 00396 // Work out if this is a repeating stroke, and if so, how often it repeats 00397 if (CreateSubRenderContext) 00398 { 00399 if (pStrokeDef->IsRepeating()) 00400 { 00401 // The repeat distance is calculated as a number of millipoints per repeat of the 00402 // stroke, such that it retains the correct aspect ratio. That is, the ratio of 00403 // brush width to height is the same as RepeatDist to LineWidth 00404 pSubRenderContext->RepeatDist = (INT32) (Stroker.GetScaleFactor() * (double)BrushBounds.Width()); 00405 if (pSubRenderContext->RepeatDist < 1000) // I absolutely refuse to repeat it more than 00406 pSubRenderContext->RepeatDist = 1000; // once every 1pt, as this is plenty small enough 00407 00408 // Suss the path length out 00409 ProcessLength GenerateLength(100); 00410 double Length = 0; 00411 BOOL ok = GenerateLength.PathLength(pPath, &Length); 00412 00413 // Ask the stroke def for its number of brush repeats - 0 means work it out 00414 INT32 NumberOfRepeats = pStrokeDef->NumRepeats(); 00415 if(NumberOfRepeats == 0 && pSubRenderContext->RepeatDist > 0) 00416 { 00417 // Work out the optimal number of repeats along the path 00418 NumberOfRepeats = (INT32)(floor((Length/pSubRenderContext->RepeatDist) + 0.5)); 00419 } 00420 00421 // Don't got dividing by zero now... 00422 if(NumberOfRepeats <= 0) 00423 NumberOfRepeats = 1; 00424 00425 // Alter the repeat distance to accomodate this number of repeats 00426 pSubRenderContext->RepeatDist = (INT32)(Length / (double)NumberOfRepeats); 00427 } 00428 00429 // Generate the set of trapezoids for the dest path 00430 ProcessPathToTrapezoids GenerateTraps(100); 00431 pSubRenderContext->pOutputTraps = new TrapsList(pSubRenderContext->RepeatDist); 00432 00433 BOOL Failed = (pSubRenderContext->pOutputTraps == NULL); 00434 if (!Failed && !GenerateTraps.Init(pPath, pSubRenderContext->pOutputTraps)) 00435 Failed = TRUE; 00436 00437 ProcessFlags PFlags(TRUE, FALSE, FALSE); // Flags are: Flatten, !QuantiseLines, !QuantiseAll 00438 if (!Failed && !GenerateTraps.Process(PFlags, TrapTravel_Parametric, pSubRenderContext->JoinStyle)) 00439 Failed = TRUE; 00440 00441 if (Failed) 00442 { 00443 pRender->DrawPath(pPath, this, ShapePath); 00444 if (!pRender->IsSubRenderStateLocked()) 00445 pRender->SetSubRenderState(NULL); 00446 delete pSubRenderContext; 00447 return; 00448 } 00449 } 00450 00451 ERROR3IF(pSubRenderContext->pOutputTraps == NULL || pValFunc == NULL, 00452 "Vector stroke SubRenderContext was not properly uninitialised!"); 00453 00454 // --- Handle background rendering. We always store all critical information in a SubRenderContext. 00455 // If we have to break into rendering because of background rendering, we give the context to the RndRgn 00456 // to keep for next time. However, when we finish rendering everything, we need to clean up - we will 00457 // assume that we'll make it to the end, and chnage this variable if we get interrupted. 00458 BOOL DeleteSubRenderContext = TRUE; 00459 00460 // Lock the sub-render context so that nobody "inside" the brush uses it 00461 const BOOL SRContextLocked = pRender->IsSubRenderStateLocked(); 00462 if (!SRContextLocked) 00463 pRender->LockSubRenderState(TRUE); 00464 00465 // --- Now "render" the brush clipart tree via our Stroker 00466 for ( ; 00467 pSubRenderContext->Index < pSubRenderContext->pOutputTraps->GetNumTraps() && DeleteSubRenderContext; 00468 pSubRenderContext->Index++) 00469 { 00470 // Find the trapezoid edge list for this pass 00471 TrapEdgeList *pEdgeList = pSubRenderContext->pOutputTraps->GetTrapEdgeList(pSubRenderContext->Index); 00472 if (pEdgeList->GetNumEdges() < 2) 00473 { 00474 ERROR3("No map traps when stroking! Subpath stripped\n"); 00475 continue; 00476 } 00477 00478 // And render away 00479 pRender->SaveContext(); 00480 00481 Node* pNode = pBrush->FindFirstForUnclippedInkRender(pRender); 00482 while (pNode) 00483 { 00484 // Prepare the stroker to stroke this sub-stroke 00485 Stroker.PrepareToStroke(pEdgeList); 00486 00487 if (pNode->IsAnAttribute()) 00488 { 00489 // If we are overriding the fill/transparency with the one applied to the stroke, 00490 // then we simply throw away all fill/transparency attributes as we render 00491 // (We do this on the fly rather than as we make the brush so that the user can 00492 // toggle this mode on and off at any time if they change their mind) 00493 BOOL RenderIt = TRUE; 00494 if ( (pStrokeDef->OverrideFill() && ((NodeAttribute *)pNode)->IsAColourFill()) || 00495 (pStrokeDef->OverrideFill() && ((NodeAttribute *)pNode)->IsAStrokeColour()) || 00496 (pStrokeDef->OverrideTrans() && ((NodeAttribute *)pNode)->IsAStrokeTransp()) || 00497 (pStrokeDef->OverrideTrans() && ((NodeAttribute *)pNode)->IsATranspFill()) ) 00498 { 00499 RenderIt = FALSE; 00500 } 00501 00502 if (RenderIt) 00503 { 00504 // We must modify all attributes to lie in the destination stroke. 00505 // This includes fill/trans geometry endpoints, line widths, and 00506 // also possibly modifying transparency levels to allow a flat transparency 00507 // to be applied to the whole stroke. 00508 AttributeValue *pAttrValue = ((NodeAttribute *)pNode)->GetAttributeValue(); 00509 AttributeValue *pNewValue = pAttrValue->MouldIntoStroke(&Stroker, 1.0); 00510 //****!!!!TODO - Just above, we have the chance to handle transparency better 00511 // - we could at least scale all transparencies by passing a flat scale factor into 00512 // the MouldIntoStroke call. 00513 00514 if (pNewValue != NULL) 00515 pNewValue->Render(pRender, TRUE); // The RndRgn will delete this when it's done with 00516 else 00517 pNode->Render(pRender); // No change, so render the original attribute 00518 } 00519 } 00520 else if (pNode->IsNodePath()) 00521 { 00522 // Stroke the trapezoids into the output path 00523 pOutput->ClearPath(); 00524 if (!Stroker.StrokePath(&((NodePath *)pNode)->InkPath, pOutput)) 00525 break; 00526 00527 pRender->SetWindingRule(NonZeroWinding); 00528 pRender->DrawPath(pOutput, this, ShapePath); 00529 } 00530 // else 00531 // TRACEUSER( "Jason", _T("\nBrush node %s not rendered\n"), pNode->GetRuntimeClass()->m_lpszClassName); 00532 00533 pNode = pNode->FindNextForUnclippedInkRender(pRender); 00534 } 00535 00536 pRender->RestoreContext(); 00537 00538 // --- Now check if we should break into rendering for background rendering purposes 00539 // If the Sub-render-context is locked, then we're inside a blend or something, and it's too dangerous 00540 // for us to store our sub-render state, so we have no choice but to render until we finish. 00541 // BLOCK 00542 if (!SRContextLocked && IS_A(pRender, GRenderDIB)) 00543 { 00544 View *pView = pRender->GetRenderView(); 00545 if (pView != NULL && !pRender->RenderTreeCanContinue()) 00546 { 00547 // We have been interrupted by the background redraw system. 00548 // We will immediately exit, storing our SubRenderContext away into the 00549 // RenderRegion for the next time it calls us (see below). 00550 DeleteSubRenderContext = FALSE; 00551 00552 // Drop through and let the loop condition handle exit 00553 } 00554 } 00555 } 00556 00557 // If we locked the sub-render context, then we must restore it 00558 if (!SRContextLocked) 00559 pRender->LockSubRenderState(FALSE); 00560 00561 // If we have finished rendering everything, then we vape our sub render context. 00562 // (We even check if we were interrupted just as we finished the final iteration) 00563 if (DeleteSubRenderContext || pSubRenderContext->Index >= pSubRenderContext->pOutputTraps->GetNumTraps()) 00564 { 00565 if (!SRContextLocked) 00566 pRender->SetSubRenderState(NULL); 00567 delete pSubRenderContext; 00568 pSubRenderContext = NULL; 00569 } 00570 else 00571 { 00572 if (!SRContextLocked) 00573 pRender->SetSubRenderState(pSubRenderContext); 00574 } 00575 00576 delete pOutput; 00577 pOutput = NULL; 00578 #endif 00579 }
|
|
Sets this path processor up to use the given vector stroke definition in all future rendering.
Definition at line 664 of file ppvecstr.cpp. 00665 { 00666 ERROR3IF(Handle != StrokeHandle_NoStroke && StrokeComponent::FindStroke == NULL, 00667 "Trying to set a Stroke PathProcessor to use a deleted stroke!"); 00668 00669 StrokeID = Handle; 00670 }
|
|
Called by the RenderRegion to determine if this PathProcessorStrokeVector affects the "fill" and "stroke" portions of the path separately. (Generally speaking, only fill/stroke providers will cause these two different "bits" of a path to be rendered separately). This call is made BEFORE this Processor's ProcessPath function will be called.
Notes: Base class implementation returns FALSE. Derived Stroke and Fill processors (such as this one) override this method to return TRUE. Reimplemented from PathProcessorStroke. Definition at line 204 of file ppvecstr.cpp. 00205 { 00206 return(TRUE); 00207 }
|
|
Reimplemented from PathProcessorStroke. Definition at line 136 of file ppvecstr.h. |
|
Definition at line 154 of file ppvecstr.h. |