void ImagemapRenderRegion::AddPathToImagemap(Path* ppthToAdd, WebAddressAttribute* pwaaCurrent) { //First get the origin of the export area and the DPI DocCoord dcOrigin=ImagemapFilterOptions::GetOriginOfExportArea(m_Options.m_stExportArea); double dDPI=m_Options.m_dDPI; //Now, how many subpaths are there in this path? INT32 lNumSubpaths=ppthToAdd->GetNumSubpaths(); //For each subpath in the path for (INT32 l=0; l<lNumSubpaths; l++) { //Create a new path Path pthSubpath; pthSubpath.Initialise(ppthToAdd->GetNumCoords()); //And copy the next subpath into it ppthToAdd->MakePathFromSubPath(l, &pthSubpath); //Now, if that subpath is closed if (pthSubpath.IsSubPathClosed(0)) { //Then we want to add it to the imagemap //So scale it to dDPI and by dcOrigin pthSubpath.Scale(dcOrigin, dDPI); //Now we need to flatten it. //This means creating a new path, because otherwise Path::Flatten //goes wrong Path pthFlattened; pthFlattened.Initialise(pthSubpath.GetNumCoords()); //So, if we should flatten the path if (m_Options.m_ffApprox!=FF_NOTATALL) //Then do it pthSubpath.Flatten(m_Options.m_ffApprox, &pthFlattened); else //Otherwise, simply copy the path across pthFlattened.CopyPathDataFrom(&pthSubpath); //Then add the flattened path to the imagemap m_Imagemap.AddPolygon(&pthFlattened, pwaaCurrent->m_url.GetWebAddress(), pwaaCurrent->m_pcFrame); } } }
void MouldGeometry::MouldPathRender(Path* pPath, RenderRegion* pRegion) { Path RenderPath; if (!(RenderPath.Initialise(12,12))) return; if (!MouldPathToPath(pPath,&RenderPath)) return; pRegion->DrawPath(&RenderPath); }
DocRect ArrowRec::FindBoundsAt(const DocCoord& ArrowCentre, const DocCoord& Direction, INT32 ParentLineWidth) { DocRect Bounds(0,0,0,0); // Find a matrix to transform the ArrowHead to this Position. Trans2DMatrix Trans; GetArrowMatrix(ArrowCentre, Direction, ParentLineWidth, &Trans); // Note: // We should really be able to ask Gavin to Calculate the Bounds, // and pass him this Transform Matrix, but he can't do this at the // moment, so we'll have to actually transform the path into // a tempory path, and then ask him to calc the bounds of that. // Make a tempory path to transform Path* TransPath = new Path(); if (TransPath == NULL) return Bounds; // Copy the path data from the ArrorHead into our tempory path. BOOL ok = TransPath->Initialise(ArrowShape->GetNumCoords()); if (ok) ok = TransPath->CopyPathDataFrom(ArrowShape); if (!ok) { // Tidy up if we failed delete TransPath; return Bounds; } // Go transform the Tempory path Trans.Transform(TransPath->GetCoordArray(), TransPath->GetNumCoords() ); BOOL GDrawResult = FALSE; // Find out what the paths bounding rect is, taking into account // any bezier curve thingies. GDrawContext *GD = GRenderRegion::GetStaticDrawContext(); if (GD != NULL) GDrawResult = GD->CalcStrokeBBox((POINT*)TransPath->GetCoordArray(), TransPath->GetVerbArray(), TransPath->GetNumCoords(), (RECT *)(&Bounds), TRUE, 0, CAPS_ROUND, JOIN_ROUND, NULL) == 0; // If Gavin failed, then use backup technique of getting coord array bounds if (!GDrawResult) Bounds = TransPath->GetBoundingRect(); // Delete the temporary transformed path delete TransPath; return Bounds; }
void ImagemapRenderRegion::AddCircleToImagemap(Path* ppthToScale, WebAddressAttribute* pwaaCurrent) { //First get the origin of the export area and the DPI DocCoord dcOrigin=ImagemapFilterOptions::GetOriginOfExportArea(m_Options.m_stExportArea); double dDPI=m_Options.m_dDPI; //Now make a copy of the path Path pthToAdd; pthToAdd.Initialise(ppthToScale->GetNumCoords()); pthToAdd.CopyPathDataFrom(ppthToScale); //Scale it pthToAdd.Scale(dcOrigin, dDPI); //And add it to the imagemap m_Imagemap.AddCircle(&pthToAdd, pwaaCurrent->m_url.GetWebAddress(), pwaaCurrent->m_pcFrame); }
BOOL ArrowRec::CreateStockArrow(StockArrow ArrowType) { if (ArrowShape != NULL) { delete ArrowShape; ArrowShape = NULL; } BOOL ok; Path* pPath; const INT32 Size = 3; const INT32 Width = (72000/2)*3; if (ArrowType >= NUM_STOCK_ARROWS) ArrowType = SA_STRAIGHTARROW; // Set the ArrowID ArrowID = ArrowType; switch (ArrowType) { case SA_STRAIGHTARROW: /* STRAIGHT -9 54 m -9 0 l -9 -54 l 117 0 l -9 54 l -9 54 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(4); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord( -9000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( -9000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord(117000, 0)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = FALSE; break; case SA_ANGLEDARROW: /* ANGLED -26.999 53.999 m -9 0 l -26.999 -54.001 l 135 0 l -26.999 53.999 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(5); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord(-27000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( -9000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord(-27000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord(135000, 0)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = FALSE; break; case SA_ROUNDEDARROW: /* ROUND -9 0 m -9 -45 l -9 -51.708 2.808 -56.580 9 -54 c 117 -9 l 120.916 -7.369 126 -4.242 126 0 c 126 4.242 120.916 7.369 117 9 c 9 54 l 2.808 56.580 -9 51.708 -9 45 c -9 0 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(17); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo( DocCoord( -9000, 0)); if (ok) ok = pPath->InsertLineTo( DocCoord( -9000, -45000)); if (ok) ok = pPath->InsertCurveTo(DocCoord( -9000, -51708), DocCoord( 2808, -56580), DocCoord( 9000, -54000)); if (ok) ok = pPath->InsertLineTo( DocCoord( 117000, -9000)); if (ok) ok = pPath->InsertCurveTo(DocCoord( 120916, -7369), DocCoord( 126000, -4242), DocCoord( 126000, 0)); if (ok) ok = pPath->InsertCurveTo(DocCoord( 126000, 4242), DocCoord( 120916, 7369), DocCoord( 117000, 9000)); if (ok) ok = pPath->InsertLineTo( DocCoord( 9000, 54000)); if (ok) ok = pPath->InsertCurveTo(DocCoord( 2808, 56580), DocCoord( -9000, 51708), DocCoord( -9000, 45000)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = FALSE; break; case SA_SPOT: /* BLOB -54 0 m -54 29.807 -29.807 54 0 54 c 29.807 54 54 29.807 54 0 c 54 -29.807 29.807 -54 0 -54 c -29.807 -54 -54 -29.807 -54 0 c */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(14); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo( DocCoord( -54000, 0)); if (ok) ok = pPath->InsertCurveTo(DocCoord( -54000, 29807), DocCoord( -29807, 54000), DocCoord( 0, 54000)); if (ok) ok = pPath->InsertCurveTo(DocCoord( 29807, 54000), DocCoord( 54000, 29807), DocCoord( 54000, 0)); if (ok) ok = pPath->InsertCurveTo(DocCoord( 54000, -29807), DocCoord( 29807, -54000), DocCoord( 0, -54000)); if (ok) ok = pPath->InsertCurveTo(DocCoord( -29807, -54000), DocCoord( -54000, -29807), DocCoord( -54000, 0)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = TRUE; break; case SA_DIAMOND: /* DIAMOND -63 0 m 0 63 l 63 0 l 0 -63 l -63 0 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(5); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord(-63000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord( 0, 63000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord( 0, -63000)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = TRUE; break; case SA_ARROWFEATHER: /* FEATHER 18 -54 m 108 -54 l 63 0 l 108 54 l 18 54 l -36 0 l 18 -54 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(7); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord( 18000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord(108000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord(108000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 18000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord(-36000, 0)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = TRUE; break; case SA_ARROWFEATHER2: /* FEATHER3 -35.998 0 m 18 -54 l 54 -54 l 18 -18 l 27 -18 l 63 -54 l 99 -54 l 63 -18 l 72 -18 l 108 -54 l 144 -54 l 90 0 l 144 54 l 108 54 l 72 18 l 63 18 l 99 54 l 63 54 l 27 18 l 18 18 l 54 54 l 18 54 l -35.998 0 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(23); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord( -36000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord( 18000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 54000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 18000, -18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 27000, -18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 99000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, -18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 72000, -18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 108000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 144000, -54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 90000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord( 144000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 108000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 72000, 18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, 18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 99000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 27000, 18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 18000, 18000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 54000, 54000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 18000, 54000)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(0,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = TRUE; break; case SA_HOLLOWDIAMOND: /* HOLLOW 0 45 m -45 0 l 0 -45 l 45 0 l 0 45 l 0 63 m -63 0 l 0 -63 l 63 0 l 0 63 l */ pPath = new Path(); if (pPath == NULL) return FALSE; ok = pPath->Initialise(10); if (ok) pPath->FindStartOfPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord( 0, 45000)); if (ok) ok = pPath->InsertLineTo(DocCoord(-45000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord( 0, -45000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 45000, 0)); if (ok) ok = pPath->CloseSubPath(); if (ok) ok = pPath->InsertMoveTo(DocCoord( 0, 63000)); if (ok) ok = pPath->InsertLineTo(DocCoord(-63000, 0)); if (ok) ok = pPath->InsertLineTo(DocCoord( 0, -63000)); if (ok) ok = pPath->InsertLineTo(DocCoord( 63000, 0)); if (ok) ok = pPath->CloseSubPath(); if (!ok) { delete pPath; return FALSE; } pPath->IsFilled = TRUE; pPath->IsStroked = FALSE; ArrowShape = pPath; Centre = DocCoord(-45000,0); LineWidth = Width; ArrowWidth = INT32(Size); ArrowHeight = INT32(Size); IsNull = FALSE; StartArrow = TRUE; break; default: ArrowShape = NULL; Centre = DocCoord(0,0); LineWidth = DEFAULT_ARROW_LINEWIDTH; ArrowWidth = 3; ArrowHeight = 3; StartArrow = FALSE; ScaleWithLineWidth = TRUE; ArrowID = SA_NULLARROW; IsNull = TRUE; break; } return TRUE; }
BOOL StringToBitmap::TTFAddString(String_256 *text, UINT32 Xsize, UINT32 Ysize, UINT32 DPI, PLOGFONT pLogFont, INT32 IntLeading, KernelBitmap **BM, UINT32 ForeColour) { KernelBitmap *Bitmap = *BM; /* HDC ScreenDC = CreateCompatibleDC(NULL); if (ScreenDC == NULL) { ERROR3("StringToBitmap::AddString: Unable to create screen DC"); return FALSE; }*/ CDC SysDisplay; BOOL ok=SysDisplay.CreateCompatibleDC(NULL); if(!ok) { //DeleteDC(ScreenDC); ERROR3("StringToBitmap::TTF AddString: Unable to create CDC"); return FALSE; } HDC ScreenDC = SysDisplay.m_hDC; // bodge to get things working with GetBezierFromChar INT32 OldlfHeight = pLogFont->lfHeight; pLogFont->lfHeight = -(pLogFont->lfHeight - IntLeading); UINT32 CurrentPathSizeAlloc = 0; Trans2DMatrix *pTransform = NULL; DocCoord *pPathCoords = NULL; Path *pPath = NULL; //pPath = new Path(); DocCoord *pPolyCordBuffer = NULL; PathVerb *pPolyVerbBuffer = NULL; UINT32 TextLength = (UINT32)text->Length(); SIZE StringSize= {0,0}; // Get handle of font // HFONT hNewFont = CreateFontIndirect(pLogFont); // HGDIOBJ hOldFont = SelectObject(ScreenDC, hNewFont); CFont UnHintedCFont; if(!UnHintedCFont.CreateFontIndirect(pLogFont)) { SysDisplay.DeleteDC(); pLogFont->lfHeight = OldlfHeight; return FALSE; } CFont* pOldCFont=SysDisplay.SelectObject(&UnHintedCFont); // Get the default character to use if a charater is not present in the font. WCHAR FontDefaultCharacter = (unsigned char)'?'; TEXTMETRIC FontTextData; #ifdef _UNCCODE if (SysDisplay.GetTextMetrics(&FontTextData)) FontDefaultCharacter = FontTextData.tmDefaultChar; #else if (SysDisplay.GetTextMetrics(&FontTextData)) FontDefaultCharacter = (unsigned char)FontTextData.tmDefaultChar; #endif // Work out a nice scaling factor so the font fits in the bitmap ok... // Not 32 ? GetTextExtentPoint(ScreenDC, *text, TextLength, &StringSize); if(StringSize.cy == 0) { SysDisplay.SelectObject(pOldCFont); SysDisplay.DeleteDC(); pLogFont->lfHeight = OldlfHeight; return FALSE; } //ERROR3IF(!ok, "Initial GetTextExtentPoint32() failed"); double YScale = ((double)Ysize / (double)StringSize.cy) / (double)2; double XScale = YScale; // Shift thumbnail upwards, and scale down a bit - to get the g's looking right // One or two fonts require this reducing (their tops are clipped), 72000/100 is // about right for most of them though... // Note the external previews were done with 72000/220 for Matrix and 72000/140 for // the capital only fonts. double YShift = 72000/100;//72000/80; YScale = (YScale * 78) / 100; XScale = (XScale * 78) / 100; if(!text->IsEmpty()) { const TCHAR* pCurrentChar = (const TCHAR*)(*text); while (ok && *pCurrentChar!=0) { // Get the current character as Unicode. #ifdef _UNICODE WCHAR wchr = *pCurrentChar; // pCurrentChar is a pointer to WCHAR in _UNICODE builds #else UINT32 CharToConvert = 0; if (UnicodeManager::IsDBCSLeadByte(*pCurrentChar)) CharToConvert = UnicodeManager::ComposeMultiBytes(*pCurrentChar, *(pCurrentChar+1)); else CharToConvert = (unsigned char)(*pCurrentChar); WCHAR wchr = UnicodeManager::MultiByteToUnicode(CharToConvert); #endif // Get positioning information for this character ok = GetTextExtentPoint(ScreenDC, *text, (pCurrentChar-(TCHAR*)(*text)), &StringSize); ERROR3IF(!ok, "GetTextExtentPoint32() failed"); if (!ok) break; // Get the characters path DWORD PathSize = 0; ok = TextManager::GetBezierFromChar(&SysDisplay, wchr, pLogFont, &PathSize, (POINT *)NULL, (BYTE *)NULL); if (!ok) { wchr = FontDefaultCharacter; ok = TextManager::GetBezierFromChar(&SysDisplay, wchr, pLogFont, &PathSize, (POINT *)NULL, (BYTE *)NULL); } ERROR3IF(!ok, "GetBezierFromChar returned false"); if (!ok) break; // Pointer to an array of path coordinates if(pPolyCordBuffer == NULL) { TRY { pPolyCordBuffer = new DocCoord[PathSize]; } CATCH (CMemoryException, e) { pPolyCordBuffer = NULL; /*ERROR(_R(IDS_OUT_OF_MEMORY), FALSE);*/ } END_CATCH } // Pointer to an array of path verbs if(pPolyVerbBuffer == NULL) { TRY { pPolyVerbBuffer = new PathVerb[PathSize]; } CATCH (CMemoryException, e) { pPolyVerbBuffer = NULL; /*ERROR(_R(IDS_OUT_OF_MEMORY), FALSE);*/ } END_CATCH } if (pPolyCordBuffer == NULL || pPolyVerbBuffer == NULL) { ok = FALSE; break; } CurrentPathSizeAlloc = PathSize; // Fill up the buffers until they're bursting with fontyness ok = TextManager::GetBezierFromChar(&SysDisplay, wchr, pLogFont, &PathSize, (POINT *)pPolyCordBuffer, (BYTE *)pPolyVerbBuffer); if(!ok) TRACEUSER( "Richard", _T("GetBezierFromChar returned false in second phase...\n")); if(!ok) break; // Spaces set PathSize to zero if((PathSize > 0)/* && (pPath != NULL)*/) { pPath = new Path(); pPath->Initialise(PathSize, 12); pPath->CopyPathDataFrom(pPolyCordBuffer, pPolyVerbBuffer, PathSize, TRUE); // Major bodge at present with the x spacing... Matrix scale(XScale, 0, 0, YScale, (INT32)((XScale*StringSize.cx*72000)/(double)DPI), (INT32)YShift); pTransform = new Trans2DMatrix(scale); pPathCoords = pPath->GetCoordArray(); pTransform->Transform( pPathCoords, pPath->GetNumCoords() ); delete pTransform; pPath->InitialiseFlags(); ok = ALU->GradFillPath(pPath, ForeColour, ForeColour, 0, 0, 0,/*Xsize/2,*/ Ysize, S2BMP_ANTIALIAS); ERROR3IF(!ok, "Gradfillpath returned false"); if(!ok) break; delete pPath; } // S2BMP_MAGIC is the worderfully fabby constant that mark's getbezierfromchar returns // Theory goes that he's going to sort this out sometime... if(CurrentPathSizeAlloc != S2BMP_MAGIC) { delete []pPolyCordBuffer; delete []pPolyVerbBuffer; pPolyCordBuffer = NULL; pPolyVerbBuffer = NULL; CurrentPathSizeAlloc = 0; } pPath = NULL; pTransform = NULL; pCurrentChar = camStrinc(pCurrentChar); }
void PathProcessorStrokeAirbrush::ProcessPath(Path *pPath, RenderRegion *pRender, PathShape ShapePath) { PORTNOTETRACE("other","PathProcessorStrokeAirbrush::ProcessPath - do nothing"); #ifndef EXCLUDE_FROM_XARALX ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params"); // --- If the provided path is not stroked, then we'll just pass it straight through // We also don't touch it if we're doing EOR rendering, or click regions // BLOCK { StrokeColourAttribute *pStrokeColour = (StrokeColourAttribute *) pRender->GetCurrentAttribute(ATTR_STROKECOLOUR); if (pRender->DrawingMode != DM_COPYPEN || pRender->IsHitDetect() || !pPath->IsStroked || pStrokeColour == NULL || pStrokeColour->Colour.IsTransparent()) { pRender->DrawPath(pPath, this, ShapePath); return; } } // --- If the quality is set low, strokes are just rendered as centrelines // BLOCK { QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY); if (pQuality != NULL && pQuality->QualityValue.GetLineQuality() != Quality::FullLine) { pRender->DrawPath(pPath, this, ShapePath); return; } } // --- If the attribute which created us is not the current StrokeType attribute, then // we have been overridden by a different stroke type, so we do nothing. // BLOCK { StrokeTypeAttrValue *pTypeAttr = (StrokeTypeAttrValue *) pRender->GetCurrentAttribute(ATTR_STROKETYPE); if (pTypeAttr != NULL && pTypeAttr != GetParentAttr()) { pRender->DrawPath(pPath, this, ShapePath); return; } } // --- Get the current line width from the render region // In case of failure, we initialise with suitable defaults INT32 LineWidth = 5000; // BLOCK { LineWidthAttribute *pWidthAttr = (LineWidthAttribute *) pRender->GetCurrentAttribute(ATTR_LINEWIDTH); if (pWidthAttr != NULL) LineWidth = pWidthAttr->LineWidth; } // Obtain an optimal number of steps for the line // When printing, we do heaps of steps to get top quality out the other end View *pView = pRender->GetRenderView(); ERROR3IF(pView == NULL, "No render view?!"); INT32 NumSteps = MaxAirbrushSteps; if (!pRender->IsPrinting()) GetNumSteps(pView, LineWidth); // --- Now, create a transparency mask bitmap for the airbrush Spread *pSpread = pRender->GetRenderSpread(); // ERROR3IF(pSpread == NULL, "No render spread!?"); // This can happen, rendering into a gallery // Get the render region's clip rectangle in Spread Coords. We don't need to // render anything bigger than this size, so it is the upper limit on our bitmap area. DocRect ClipRegion = pRender->GetClipRect(); // Intersect this with the path bounding rectangle to get the actual region we need to redraw // The smaller this is, the faster we go and the less memory we use. //DocRect PathRect = pPath->GetBoundingRect(); DocRect PathRect = pPath->GetBlobRect(); PathRect.Inflate(LineWidth); BOOL Intersects = ClipRegion.IsIntersectedWith(PathRect); if(!Intersects) { // Don't bother drawing anything - it's clipped out return; } ClipRegion = ClipRegion.Intersection(PathRect); // Round the ClipRegion edges up so they all lie exactly on screen pixel boundaries. // If we don't do this, then there can be a sub-pixel rounding error between the ClipRegion // and the actual bitmap size, so that the bitmap is scaled slightly when we plot it. // By making sure it's pixelised, we guarantee that the bitmap & clipregion are exactly equal sizes. // (It doesn't matter if the bitmap is a bit bigger than necessary) ClipRegion.Inflate(pRender->GetScaledPixelWidth()); ClipRegion.lo.Pixelise(pView); ClipRegion.hi.Pixelise(pView); // Get the current view's rendering matrix and view scale Matrix ConvMatrix = pRender->GetMatrix();//pView->ConstructRenderingMatrix(pSpread); FIXED16 ViewScale = pView->GetViewScale(); // Generate a 256-colour greyscale palette LOGPALETTE *pPalette = MakeGreyScalePalette(); if(pPalette == NULL) { pRender->DrawPath(pPath, this, ShapePath); return; } // Work out the DPI to use. Rather than just asking for PixelWidth or DPI from the // render region, we have to do a load of non-object-oriented stuff instead... double dpi = 96.0; if (pRender->IsPrinting()) { // we are printing, so ask the print options PrintControl *pPrintControl = pView->GetPrintControl(); if (pPrintControl != NULL) dpi = (double) pPrintControl->GetDotsPerInch(); } else if (IS_A(pRender, CamelotEPSRenderRegion)) { // Use DPI as set in EPS export options dialog. dpi = (double) EPSFilter::XSEPSExportDPI; } else { ERROR3IF(pRender->GetPixelWidth() <= 0, "Stupid (<1 millipoint) Pixel Width!"); if (pRender->GetPixelWidth() > 0) dpi = (double) (72000.0 / (double)pRender->GetPixelWidth()); } GRenderBitmap *pMaskRegion = new GRenderBitmap(ClipRegion, ConvMatrix, ViewScale, 8, dpi, pRender->IsPrinting(), XARADITHER_ORDERED_GREY, pPalette, FALSE); if (pMaskRegion == NULL) { pRender->DrawPath(pPath, this, ShapePath); return; } BOOL PathIsFilled = FALSE; // Will be set TRUE if this path should be filled at the bottom of the function //BLOCK { // Change the GDraw context in this render region so as to preserve the state // of the main render region. This is because GRenderRegions currently use // a single static GDrawContext! This also sets it up with a nice greyscale palette // so that we get the output we desire. pMaskRegion->UseGreyscaleContextDangerous(); // Attach our DC to the view and render region... if (pMaskRegion->AttachDevice(pView, NULL, pSpread)) { pMaskRegion->StartRender(); // We must save & restore the attribute state around all our rendering because // attributes otherwise stay on the renderstack until we delete the RndRgn, and as our // ones are on the program stack, they will have ceased to exist before then, which // makes for a wicked explosion. pMaskRegion->SaveContext(); ///////////////////////////////////////////////////////////////////////////////////// // --- Main Airbrush rendering loop // Make sure we've got an intensity function to use. This will create a new one if necessary ValueFunction *pvValueFunction = GetIntensityFunction(); if (pvValueFunction == NULL) { ERROR3("Failed to set an intensity function on an airbrush stroke"); pRender->DrawPath(pPath, this, ShapePath); return; } if(!RenderAirBrush(pPath, pMaskRegion, LineWidth, NumSteps, pvValueFunction, pRender, ShapePath)) { // Airbrush failed - just render the path without the airbrush effect pRender->DrawPath(pPath, this, ShapePath); return; } pMaskRegion->RestoreContext(); // --- ClipRect test code ///////////////////////////////////////////////////////////////////////////////////// // --- We have drawn the airbrushed stroke - now, if the path is filled, we // will render the filled area, so that in semi-transparent cases, the // stroke will not "show through" from behind the filled area. if (pPath->IsFilled) { ColourFillAttribute *pCFAttr = (ColourFillAttribute *) pRender->GetCurrentAttribute(ATTR_FILLGEOMETRY); if (pCFAttr != NULL && (!pCFAttr->Colour.IsTransparent() || pCFAttr->IsABitmapFill())) { PathIsFilled = TRUE; pMaskRegion->SaveContext(); ColourFillAttribute *pFillAttr = NULL; FillMappingAttribute *pMapAttr = NULL; // Obtain the object's transparent fill geometry TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY); if (pTransAttr != NULL) { // Get a non-transparent version of the fill geometry pFillAttr = pTransAttr->MakeSimilarNonTranspFillGeometry(1.0); // Convert a fill mapping TranspFillMappingAttribute *pTransMapAttr = (TranspFillMappingAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLMAPPING); if(pTransMapAttr != NULL) pMapAttr = pTransMapAttr->MakeSimilarNonTranspFillMapping(); } // Setup region and draw path into it if (pFillAttr != NULL) { pMaskRegion->SetFillGeometry(pFillAttr, TRUE); if(pMapAttr != NULL) pMaskRegion->SetFillMapping(pMapAttr, TRUE); } else pMaskRegion->SetFillColour(DocColour(0, 0, 0)); pMaskRegion->SetLineColour(DocColour(COLOUR_TRANS)); pMaskRegion->DrawPath(pPath, NULL, ShapePath); pMaskRegion->RestoreContext(); } } pMaskRegion->StopRender(); } pMaskRegion->StopUsingGreyscaleContextDangerous(); } // Extract the transparency mask bitmap from the render region OILBitmap *pOilBmp = pMaskRegion->ExtractBitmap(); // We no longer need the RenderRegion, so scrap it. delete pMaskRegion; pMaskRegion = NULL; pPalette = NULL; // Now, render a rectangle to the output render region, using the transparency mask if (pOilBmp == NULL) return; KernelBitmap *pMask = new KernelBitmap(pOilBmp, TRUE); if (pMask != NULL) { // Make sure the bitmap knows it's already a greyscale, else it will spend a lot of // time "converting" itself to a greyscale, and what's more, corrupting the grey levels // so that 255 (invisible) becomes 254 (slightly visible). Arrrrrgh! pMask->SetAsGreyscale(); // Create a transparency attribute from our mask bitmap BitmapTranspFillAttribute Trans; // We don't call pTrans->AttachBitmap because it seems to be stupid, and causes ructions // when we try to attach a temporary bitmap. We thus do the same thing, but avoiding // its attempts to automatically screw us about. Trans.BitmapRef.Detach(); Trans.BitmapRef.SetBitmap(pMask); Trans.SetStartPoint(&ClipRegion.lo); DocCoord EndPoint(ClipRegion.hi.x, ClipRegion.lo.y); Trans.SetEndPoint(&EndPoint); DocCoord EndPoint2(ClipRegion.lo.x, ClipRegion.hi.y); Trans.SetEndPoint2(&EndPoint2); UINT32 TValue = 0; Trans.SetStartTransp(&TValue); TValue = 255; Trans.SetEndTransp(&TValue); // Use the same transparency type as is set on the object being rendered (if any) { TranspFillAttribute *pTransAttr = (TranspFillAttribute *) pRender->GetCurrentAttribute(ATTR_TRANSPFILLGEOMETRY); if (pTransAttr != NULL) Trans.SetTranspType(pTransAttr->GetTranspType()); else Trans.SetTranspType(TT_Mix); // By default, we'll use Mix transparency } // --- OK, we finally got here! Render the stroke, using the transparency mask we just made pRender->SaveContext(); Trans.Render(pRender); // Render the path. If it is filled, then we render the entire thing (fill & stroke) using // the current fill geometry (to get a shadow/feather effect) if (PathIsFilled) { // Render the entire thing (fill & stroke) in one go. We render a rectangle over the cliprect // so that we do everything in one go (we can't render the fill &7 stroke separately, or // the transparency will overlap & it'll look wrong) pRender->SetLineColour(DocColour(COLOUR_TRANS)); // Don't render a line Path Rect; Rect.Initialise(); Rect.AddMoveTo(ClipRegion.lo); Rect.AddLineTo(DocCoord(ClipRegion.hix, ClipRegion.loy)); Rect.AddLineTo(ClipRegion.hi); Rect.AddLineTo(DocCoord(ClipRegion.lox, ClipRegion.hiy)); Rect.AddLineTo(ClipRegion.lo); Rect.IsFilled = TRUE; Rect.IsStroked = FALSE; pRender->DrawPath(&Rect, this, ShapePath); } else { // Otherwise, create a filled-outline path for the entire stroke, and render it // !!!!****ToDo - for now, strokes always render flat-filled with the stroke colour StrokeColourAttribute *pStrokeColour = (StrokeColourAttribute *) pRender->GetCurrentAttribute(ATTR_STROKECOLOUR); if (pStrokeColour != NULL) pRender->SetFillColour(pStrokeColour->Colour); // Fill the holes pRender->SetWindingRule(NonZeroWinding); Path *pOutput = CreateVarWidthStroke(pPath, pRender, LineWidth); if (pOutput != NULL) { pRender->DrawPath(pOutput, NULL, ShapePath); delete pOutput; pOutput = NULL; } } pRender->RestoreContext(); // Delete the kernel bitmap. This auto-deletes the OIL bitmap for us delete pMask; } #endif }
void PathProcessorStrokeVector::ProcessPath(Path *pPath, RenderRegion *pRender, PathShape ShapePath) { PORTNOTETRACE("other","PathProcessorStrokeVector::ProcessPath - do nothing"); #ifndef EXCLUDE_FROM_XARALX ERROR3IF(pPath == NULL || pRender == NULL, "Illegal NULL Params"); // Get the RenderRegion SubRenderContext and see if we're returning part-way through a background render VectorStrokeSubRenderContext *pSubRenderContext = (VectorStrokeSubRenderContext *)pRender->GetSubRenderState(); if (pSubRenderContext != NULL && !IS_A(pSubRenderContext, VectorStrokeSubRenderContext)) { // We can't use the sub render context, because it's not ours! pSubRenderContext = NULL; } // --- If we don't have a valid stroke definition, then get the base class to render // the stroke as a simple flat-filled stroke. StrokeDefinition *pStrokeDef = StrokeComponent::FindStroke(StrokeID); if (pStrokeDef == NULL) { PathProcessorStroke::ProcessPath(pPath, pRender); return; } // --- See if we have to create a new SubRenderContext, or if we can use the one passed in. // We always store all relevant variables in a SubRenderContext object so that we can easily // return control to the RenderRegion without having to copy lots of local values in/out. const BOOL CreateSubRenderContext = (pSubRenderContext == NULL); if (CreateSubRenderContext) { pSubRenderContext = new VectorStrokeSubRenderContext; if (pSubRenderContext == NULL) { pRender->DrawPath(pPath, this, ShapePath); return; } // --- If the provided path is not stroked, then we'll just pass it straight through // We also don't touch it if we're doing EOR rendering, or click hit detection if (!pPath->IsStroked || pRender->DrawingMode != DM_COPYPEN || pRender->IsHitDetect()) { delete pSubRenderContext; pRender->DrawPath(pPath, this, ShapePath); return; } // --- If the quality is set low, or if the current stroke attribute is not our "parent" // attribute (so we're not the "current" stroker) then strokes are just rendered as centrelines // BLOCK { QualityAttribute *pQuality = (QualityAttribute *) pRender->GetCurrentAttribute(ATTR_QUALITY); StrokeTypeAttrValue *pTypeAttr = (StrokeTypeAttrValue *) pRender->GetCurrentAttribute(ATTR_STROKETYPE); if ((pQuality != NULL && pQuality->QualityValue.GetLineQuality() != Quality::FullLine) || (pTypeAttr != NULL && pTypeAttr != GetParentAttr())) { delete pSubRenderContext; pRender->DrawPath(pPath, this, ShapePath); return; } } // --- We don't expect the input path to be stroked AND filled on entry ERROR3IF(pPath->IsFilled, "PathProcessor expected RenderRegion to handle IsFilled case"); // --- Get the current line width & Join Style from the render region // BLOCK { LineWidthAttribute *pWidthAttr = (LineWidthAttribute *) pRender->GetCurrentAttribute(ATTR_LINEWIDTH); if (pWidthAttr != NULL) pSubRenderContext->LineWidth = pWidthAttr->LineWidth; JoinTypeAttribute *pJoinAttr = (JoinTypeAttribute *) pRender->GetCurrentAttribute(ATTR_JOINTYPE); if (pJoinAttr != NULL) pSubRenderContext->JoinStyle = pJoinAttr->JoinType; } } // --- Create a new path to be rendered in place of the provided path // Note that I use a large allocation size so that reallocation need not be done // frequently, which also helps reduce memory fragmentation. Path *pOutput = new Path; if (pOutput == NULL) { if (!pRender->IsSubRenderStateLocked()) pRender->SetSubRenderState(NULL); delete pSubRenderContext; pRender->DrawPath(pPath, this, ShapePath); return; } pOutput->Initialise(128, 128); // --- Find our Variable Width function if (CreateSubRenderContext) { // --- Get the variable line width descriptor from the render region VariableWidthAttrValue *pVarWidthAttr = (VariableWidthAttrValue *) pRender->GetCurrentAttribute(ATTR_VARWIDTH); if (pVarWidthAttr != NULL) pSubRenderContext->pValFunc = pVarWidthAttr->GetWidthFunction(); } ValueFunction *pValFunc = pSubRenderContext->pValFunc; // If we couldn't find a proper value function, then we'll default to constant-width. // We keep a static Constant function around always, because it's thread-safe and because // that saves us the overhead of creating and deleting it on the stack each time we're called static ValueFunctionConstant Constant(1.0); if (pValFunc == NULL) pValFunc = &Constant; // --- Find our brush clipart tree Node *pBrush = pStrokeDef->GetStrokeTree(); ERROR3IF(!IS_A(pBrush, Spread), "Brush does not start with a Spread Node!"); DocRect BrushBounds = ((Spread *)pBrush)->GetBoundingRect(); // Get a PathStroker to map paths onto the destination stroke with PathStrokerVector Stroker(pValFunc, pSubRenderContext->LineWidth, LineCapButt, &BrushBounds); // Work out if this is a repeating stroke, and if so, how often it repeats if (CreateSubRenderContext) { if (pStrokeDef->IsRepeating()) { // The repeat distance is calculated as a number of millipoints per repeat of the // stroke, such that it retains the correct aspect ratio. That is, the ratio of // brush width to height is the same as RepeatDist to LineWidth pSubRenderContext->RepeatDist = (INT32) (Stroker.GetScaleFactor() * (double)BrushBounds.Width()); if (pSubRenderContext->RepeatDist < 1000) // I absolutely refuse to repeat it more than pSubRenderContext->RepeatDist = 1000; // once every 1pt, as this is plenty small enough // Suss the path length out ProcessLength GenerateLength(100); double Length = 0; BOOL ok = GenerateLength.PathLength(pPath, &Length); // Ask the stroke def for its number of brush repeats - 0 means work it out INT32 NumberOfRepeats = pStrokeDef->NumRepeats(); if(NumberOfRepeats == 0 && pSubRenderContext->RepeatDist > 0) { // Work out the optimal number of repeats along the path NumberOfRepeats = (INT32)(floor((Length/pSubRenderContext->RepeatDist) + 0.5)); } // Don't got dividing by zero now... if(NumberOfRepeats <= 0) NumberOfRepeats = 1; // Alter the repeat distance to accomodate this number of repeats pSubRenderContext->RepeatDist = (INT32)(Length / (double)NumberOfRepeats); } // Generate the set of trapezoids for the dest path ProcessPathToTrapezoids GenerateTraps(100); pSubRenderContext->pOutputTraps = new TrapsList(pSubRenderContext->RepeatDist); BOOL Failed = (pSubRenderContext->pOutputTraps == NULL); if (!Failed && !GenerateTraps.Init(pPath, pSubRenderContext->pOutputTraps)) Failed = TRUE; ProcessFlags PFlags(TRUE, FALSE, FALSE); // Flags are: Flatten, !QuantiseLines, !QuantiseAll if (!Failed && !GenerateTraps.Process(PFlags, TrapTravel_Parametric, pSubRenderContext->JoinStyle)) Failed = TRUE; if (Failed) { pRender->DrawPath(pPath, this, ShapePath); if (!pRender->IsSubRenderStateLocked()) pRender->SetSubRenderState(NULL); delete pSubRenderContext; return; } } ERROR3IF(pSubRenderContext->pOutputTraps == NULL || pValFunc == NULL, "Vector stroke SubRenderContext was not properly uninitialised!"); // --- Handle background rendering. We always store all critical information in a SubRenderContext. // If we have to break into rendering because of background rendering, we give the context to the RndRgn // to keep for next time. However, when we finish rendering everything, we need to clean up - we will // assume that we'll make it to the end, and chnage this variable if we get interrupted. BOOL DeleteSubRenderContext = TRUE; // Lock the sub-render context so that nobody "inside" the brush uses it const BOOL SRContextLocked = pRender->IsSubRenderStateLocked(); if (!SRContextLocked) pRender->LockSubRenderState(TRUE); // --- Now "render" the brush clipart tree via our Stroker for ( ; pSubRenderContext->Index < pSubRenderContext->pOutputTraps->GetNumTraps() && DeleteSubRenderContext; pSubRenderContext->Index++) { // Find the trapezoid edge list for this pass TrapEdgeList *pEdgeList = pSubRenderContext->pOutputTraps->GetTrapEdgeList(pSubRenderContext->Index); if (pEdgeList->GetNumEdges() < 2) { ERROR3("No map traps when stroking! Subpath stripped\n"); continue; } // And render away pRender->SaveContext(); Node* pNode = pBrush->FindFirstForUnclippedInkRender(pRender); while (pNode) { // Prepare the stroker to stroke this sub-stroke Stroker.PrepareToStroke(pEdgeList); if (pNode->IsAnAttribute()) { // If we are overriding the fill/transparency with the one applied to the stroke, // then we simply throw away all fill/transparency attributes as we render // (We do this on the fly rather than as we make the brush so that the user can // toggle this mode on and off at any time if they change their mind) BOOL RenderIt = TRUE; if ( (pStrokeDef->OverrideFill() && ((NodeAttribute *)pNode)->IsAColourFill()) || (pStrokeDef->OverrideFill() && ((NodeAttribute *)pNode)->IsAStrokeColour()) || (pStrokeDef->OverrideTrans() && ((NodeAttribute *)pNode)->IsAStrokeTransp()) || (pStrokeDef->OverrideTrans() && ((NodeAttribute *)pNode)->IsATranspFill()) ) { RenderIt = FALSE; } if (RenderIt) { // We must modify all attributes to lie in the destination stroke. // This includes fill/trans geometry endpoints, line widths, and // also possibly modifying transparency levels to allow a flat transparency // to be applied to the whole stroke. AttributeValue *pAttrValue = ((NodeAttribute *)pNode)->GetAttributeValue(); AttributeValue *pNewValue = pAttrValue->MouldIntoStroke(&Stroker, 1.0); //****!!!!TODO - Just above, we have the chance to handle transparency better // - we could at least scale all transparencies by passing a flat scale factor into // the MouldIntoStroke call. if (pNewValue != NULL) pNewValue->Render(pRender, TRUE); // The RndRgn will delete this when it's done with else pNode->Render(pRender); // No change, so render the original attribute } } else if (pNode->IsNodePath()) { // Stroke the trapezoids into the output path pOutput->ClearPath(); if (!Stroker.StrokePath(&((NodePath *)pNode)->InkPath, pOutput)) break; pRender->SetWindingRule(NonZeroWinding); pRender->DrawPath(pOutput, this, ShapePath); } // else // TRACEUSER( "Jason", _T("\nBrush node %s not rendered\n"), pNode->GetRuntimeClass()->m_lpszClassName); pNode = pNode->FindNextForUnclippedInkRender(pRender); } pRender->RestoreContext(); // --- Now check if we should break into rendering for background rendering purposes // If the Sub-render-context is locked, then we're inside a blend or something, and it's too dangerous // for us to store our sub-render state, so we have no choice but to render until we finish. // BLOCK if (!SRContextLocked && IS_A(pRender, GRenderDIB)) { View *pView = pRender->GetRenderView(); if (pView != NULL && !pRender->RenderTreeCanContinue()) { // We have been interrupted by the background redraw system. // We will immediately exit, storing our SubRenderContext away into the // RenderRegion for the next time it calls us (see below). DeleteSubRenderContext = FALSE; // Drop through and let the loop condition handle exit } } } // If we locked the sub-render context, then we must restore it if (!SRContextLocked) pRender->LockSubRenderState(FALSE); // If we have finished rendering everything, then we vape our sub render context. // (We even check if we were interrupted just as we finished the final iteration) if (DeleteSubRenderContext || pSubRenderContext->Index >= pSubRenderContext->pOutputTraps->GetNumTraps()) { if (!SRContextLocked) pRender->SetSubRenderState(NULL); delete pSubRenderContext; pSubRenderContext = NULL; } else { if (!SRContextLocked) pRender->SetSubRenderState(pSubRenderContext); } delete pOutput; pOutput = NULL; #endif }
void ArrangeAlignment::RedrawDiagram(ReDrawInfoType* ExtraInfo) { // objects drawn in the render region must be relatively large in the given coord space // else Gavin's curve flattening results in visible straight lines // so every dimension is scaled by scale INT32 scale=1000; // make a render region DocRect VirtRendRect; VirtRendRect.lo.x=-1*scale; VirtRendRect.lo.y=-2*scale; VirtRendRect.hi.x=(DiagWidth +1)*scale; VirtRendRect.hi.y=(DiagHeight+2)*scale; RenderRegion* pRender=CreateGRenderRegion(&VirtRendRect,ExtraInfo); if (pRender!=NULL) { pRender->SaveContext(); // currently this must be set here before any colour tables calculated Quality AntiAliasQuality(Quality::QualityMax); QualityAttribute AntiAliasQualityAttr(AntiAliasQuality); pRender->SetQuality(&AntiAliasQualityAttr,FALSE); // Render the background rectangle DialogColourInfo RedrawColours; pRender->SetLineColour(RedrawColours.DialogBack()); pRender->SetFillColour(RedrawColours.DialogBack()); pRender->DrawRect(&VirtRendRect); // declared at this scope else RestoreContext() dies! RadialFillAttribute Fill; // set up some defaults used by all objects Fill.MakeElliptical(); Fill.Colour=DocColour(255,255,255); pRender->SetLineColour(BLACK); pRender->SetLineWidth(0); for (INT32 i=0; i<DiagRects; i++) { // reverse order in which objets are rendered (now filled!) INT32 j=DiagRects-1-i; // set fill colour of each object switch (j) { case 0: Fill.EndColour=DocColour(255,255,0); break; case 1: Fill.EndColour=DocColour(0,0,255); break; case 2: Fill.EndColour=DocColour(255,0,0); break; case 3: Fill.EndColour=DocColour(0,160,0); break; default: Fill.EndColour=DocColour(0,0,0); break; } // get bound rect of object to be drawn INT32 x=DiagRectX[Align.h][j].lo*scale; INT32 w=DiagRectX[Align.h][j].hi*scale-x; INT32 y=DiagRectY[Align.v][j].lo*scale; INT32 h=DiagRectY[Align.v][j].hi*scale-y; // create shape and fill geometries Path shape; shape.Initialise(16,8); shape.IsFilled=TRUE; shape.FindStartOfPath(); switch (j) { case 0: { // create a rectangle shape.InsertMoveTo(DocCoord(x,y)); shape.InsertLineTo(DocCoord(x,y+h)); shape.InsertLineTo(DocCoord(x+w,y+h)); shape.InsertLineTo(DocCoord(x+w,y)); shape.InsertLineTo(DocCoord(x,y)); // // create a radial fill // Fill.StartPoint=DocCoord(x+w*3/16,y+h*3/4); // Fill.EndPoint =DocCoord(x+w*3/8,y+h/2); // Fill.EndPoint2 =DocCoord(x+w*3/8,y+h); break; } case 1: { // create a pseudo ellipse shape.InsertMoveTo( DocCoord(x,y+h/2)); shape.InsertCurveTo(DocCoord(x,y+h*3/4), DocCoord(x+w/4,y+h), DocCoord(x+w/2,y+h)); shape.InsertCurveTo(DocCoord(x+w*3/4,y+h),DocCoord(x+w,y+h*3/4),DocCoord(x+w,y+h/2)); shape.InsertCurveTo(DocCoord(x+w,y+h/4), DocCoord(x+w*3/4,y), DocCoord(x+w/2,y)); shape.InsertCurveTo(DocCoord(x+w/4,y), DocCoord(x,y+h/4), DocCoord(x,y+h/2)); // // create a radial fill // Fill.StartPoint=DocCoord(x+w*3/8,y+h*5/8); // Fill.EndPoint =DocCoord(x+w*6/8,y+h/4); // Fill.EndPoint2 =DocCoord(x+w*6/8,y+h); break; } default: { // create a rounded rectangle shape.InsertMoveTo( DocCoord(x,y+h/2)); shape.InsertCurveTo(DocCoord(x,y+h), DocCoord(x,y+h), DocCoord(x+w/2,y+h)); shape.InsertCurveTo(DocCoord(x+w,y+h),DocCoord(x+w,y+h),DocCoord(x+w,y+h/2)); shape.InsertCurveTo(DocCoord(x+w,y), DocCoord(x+w,y), DocCoord(x+w/2,y)); shape.InsertCurveTo(DocCoord(x,y), DocCoord(x,y), DocCoord(x,y+h/2)); // // create a radial fill // Fill.StartPoint=DocCoord(x+w*3/16,y+h*3/4); // Fill.EndPoint =DocCoord(x+w*3/8,y+h/2); // Fill.EndPoint2 =DocCoord(x+w*3/8,y+h); break; } } // pRender->SetFillGeometry(&Fill,FALSE); pRender->SetFillColour(Fill.EndColour); pRender->DrawPath(&shape); } pRender->RestoreContext(); DestroyGRenderRegion(pRender); // also blt's to screen } }
void RenderDemoDlg::RenderControl(ReDrawInfoType* ExtraInfo) { // Go get a render region DocRect VirtualSize(-ExtraInfo->dx/2, -ExtraInfo->dy/2, ExtraInfo->dx/2, ExtraInfo->dy/2); RenderRegion* pRender = CreateGRenderRegion(&VirtualSize, ExtraInfo); if (pRender!=NULL) { DialogColourInfo RedrawColours; // Get a supplier for default dlg colours // Render stuff in here // Build a Linear fill attribute LinearFillAttribute MyGradFill; MyGradFill.Colour = DocColour(255, 255, 0); MyGradFill.EndColour = DocColour(0, 255, 255); MyGradFill.StartPoint = DocCoord(0, ExtraInfo->dy); MyGradFill.EndPoint = DocCoord(ExtraInfo->dx, 0); // Build a path Path InkPath; InkPath.Initialise(12,12); InkPath.FindStartOfPath(); // Get the coords used to build a shape INT32 dx = ExtraInfo->dx / 2; INT32 dy = ExtraInfo->dy / 2; INT32 Midx = ExtraInfo->dx / 4; INT32 Midy = ExtraInfo->dy / 4; // build a circle in the middle of the control InkPath.InsertMoveTo(DocCoord(Midx, dy)); InkPath.InsertCurveTo(DocCoord(Midx+Midx/2, dy), DocCoord(dx, Midy+Midy/2), DocCoord(dx, Midy)); InkPath.InsertCurveTo(DocCoord(dx, Midy-Midy/2), DocCoord(Midx+Midx/2, 0), DocCoord(Midx, 0)); InkPath.InsertCurveTo(DocCoord(Midx-Midx/2, 0), DocCoord(0, Midy-Midy/2), DocCoord(0, Midy)); InkPath.InsertCurveTo(DocCoord(0, Midy+Midy/2), DocCoord(Midx-Midx/2, dy), DocCoord(Midx, dy)); InkPath.IsFilled = TRUE; // A Grey colour [...hmmm, it's not a very grey grey any more... oragnge more like] DocColour Grey(255,200,0); // Render the attributes and the a rectangle pRender->SaveContext(); pRender->SetLineColour(Grey); // Draw a rectangle to fill in the background - Fill with Dialogue Background colour DocRect DrawMe(0, 0, ExtraInfo->dx, ExtraInfo->dy); pRender->SetFillColour(RedrawColours.DialogBack()); pRender->DrawRect(&VirtualSize); // Draw some shapes and stuff pRender->SetFillGeometry(&MyGradFill, FALSE); pRender->DrawPath(&InkPath); // Build a path Path TriPath; TriPath.Initialise(12,12); TriPath.FindStartOfPath(); // build a circle in the middle of the control TriPath.InsertMoveTo(VirtualSize.lo); TriPath.InsertLineTo(DocCoord(VirtualSize.hi.x, VirtualSize.lo.y)); TriPath.InsertLineTo(DocCoord(0, VirtualSize.hi.y)); TriPath.InsertLineTo(VirtualSize.lo); TriPath.IsFilled = TRUE; LinearFillAttribute MyTriFill; MyTriFill.Colour = ShowFirst ? First : Second; MyTriFill.EndColour = DocColour(0,0,0); MyTriFill.StartPoint = DocCoord(ExtraInfo->dx, 0); MyTriFill.EndPoint = DocCoord(0, ExtraInfo->dy); pRender->SetFillGeometry(&MyTriFill, FALSE); pRender->DrawPath(&TriPath); pRender->RestoreContext(); // Get rid of the render region DestroyGRenderRegion(pRender); } // and animate it! if (ShowFirst) { INT32 Red, Green, Blue; First.GetRGBValue(&Red, &Green, &Blue); if (Blue>0) { // Set the colour back again Blue -= 10; First.SetRGBValue(Red, Green, Blue); // redraw it InvalidateGadget(_R(IDC_REDRAW_ME)); } } else { // Set the colour back to how it was First.SetRGBValue(255, 0, 250); } }
/******************************************************************************************** > BOOL BlendHelpers::BlendPaths(BlendNodeParam * pParam, Path * pPath) Author: David_McClarnon (Xara Group Ltd) <*****@*****.**> Created: 21/2/2000 Inputs: The blend node parameter Outputs: The blended path is stored in three arrays: the coords, the verbs, and the flags. The arrays are: pTempCoords pTempVerbs pTempFlags ArrayLength = the length of all three arrays This allows the caller to decide what to do with the blended path in a very flexible way. Returns: TRUE if successful, FALSE otherwise Purpose: Blends two BlendPath objects by the amount specified in BlendRatio SeeAlso: - ********************************************************************************************/ BOOL BlendHelpers::BlendPaths(BlendNodeParam * pParam, Path * pPath) { // Check entry params BlendPath * pBlendPathStart = pParam->GetStartBlendPath(); BlendPath * pBlendPathEnd = pParam->GetEndBlendPath(); ERROR2IF(!pBlendPathStart->GetBlendNode()->IsNodePath(), FALSE, "Start blend path's node isn't a node path"); ERROR2IF(!pBlendPathEnd->GetBlendNode()->IsNodePath(), FALSE, "End blend path's node isn't a node path"); BOOL ok = (pBlendPathStart != NULL && pBlendPathEnd != NULL); if (ok) ok = (pBlendPathStart->GetBlendNode() != NULL && pBlendPathEnd->GetBlendNode() != NULL); ERROR3IF(!ok,"One or more NULL entry params"); if (!ok) return FALSE; // Get the types of the two paths PathTypeEnum PathTypeStart = pBlendPathStart->GetPathType(); PathTypeEnum PathTypeEnd = pBlendPathEnd ->GetPathType(); // The blended path will be closed if either of the paths is a shape BOOL Closed = (PathTypeStart == PATHTYPE_SHAPE) || (PathTypeEnd == PATHTYPE_SHAPE); Path * pPathStart = NULL; // Find the paths associated with the start and end blend paths if (pBlendPathStart->GetBlendNode()->IsNodePath()) { pPathStart = &(((NodePath *)pBlendPathStart->GetBlendNode())->InkPath); } Path * pPathEnd = NULL; if (pBlendPathEnd->GetBlendNode()->IsNodePath()) { pPathEnd = &(((NodePath *)pBlendPathEnd->GetBlendNode())->InkPath); } // Calculate how large the arrays have to be to store the blended path definition INT32 DestPathSize = ((pPathStart->GetNumCoords()+pPathEnd->GetNumCoords())*3)+500; // Get some arrays used to hold the blended path data, and error if any are NULL DocCoord* pDestCoords = GetCoordArray(DestPathSize); PathVerb* pDestVerbs = GetVerbArray(DestPathSize); PathFlags* pDestFlags = GetFlagArray(DestPathSize); UINT32* pBuff = GetGBlendBuff(DestPathSize); if (pDestCoords == NULL || pDestVerbs == NULL || pDestFlags == NULL || pBuff == NULL) return FALSE; // This section copes with the case when blending a line with a shape. // In this case we need to get a temp path the is actually a shape version of the line. // The line is simply reversed back onto itself to form a shape that would look identical to the // line if rendered. This allows the line to appear to open up to the shape when blended. Path Shape; if (PathTypeStart != PathTypeEnd) { BOOL ok = FALSE; if (!Shape.Initialise()) return FALSE; // if going from a line to a shape, convert the start path to a shape if (PathTypeStart == PATHTYPE_LINE && PathTypeEnd == PATHTYPE_SHAPE) { ok = NodeBlender::ConvertLineToShape(pPathStart,&Shape); pPathStart = &Shape; } // if going from a shape to a line, convert the end path to a shape if (PathTypeStart == PATHTYPE_SHAPE && PathTypeEnd == PATHTYPE_LINE) { ok = NodeBlender::ConvertLineToShape(pPathEnd,&Shape); pPathEnd = &Shape; } if (!ok) return FALSE; } // The blend should do a one-to-one mapping when the OneToOne flag is set AND both paths // have the same number of elements BOOL OneToOne = FALSE; if (pParam->GetOneToOne()) OneToOne = (pBlendPathStart->GetNumElements() == pBlendPathEnd->GetNumElements()); // Now actually blend the two paths GBlend GBlendObj; // Define the blend GBlendObj.Define( (PPOINT)pPathStart->GetCoordArray(), // Specify the start path pPathStart->GetVerbArray(), pPathStart->GetNumCoords(), (PPOINT)pPathEnd ->GetCoordArray(), // Specify the end path pPathEnd ->GetVerbArray(), pPathEnd ->GetNumCoords(), OneToOne, // The one-to-one flag 1024, // Flatness pBuff, // Buffer for GBlend to use DestPathSize*sizeof(UINT32)); // The buffer size // Blend the paths m_ArrayLength = GBlendObj.Blend(pParam->GetBlendRatio(), // The blend ratio, 0.0 < BlendRatio < 1.0 (PPOINT)pDestCoords, // Array to store blended coords pDestVerbs, // Array to store blended verbs DestPathSize); // The num elements in the two arrays // If we're blending a line to another line, we need to make sure that the blended line // is going in a direction that corresponds to the source lines. This ensures attributes // that depend on this direction (e.g. start and end arrows) look correct. // // When creating blend paths of lines, we can detect if the blend path has been reversed, // in relation to the original path, by the original mapping value. // If it's 0 it has NOT been reversed, otherwise it's been reversed. // // If the blend ratio is <=0.5, the blended path is closest to the start blend path, // so we look at the start blend path's original mapping. // // If blend ration > 0.5, look at the end blend path's original mapping. // // The (BlendRation <= 0.5) cut-off point is the same as the cut-off point used in the blending // of attributes. if (pBlendPathStart->IsLine() && pBlendPathEnd->IsLine()) { BlendPath* pBlendPath; if (pParam->GetBlendRatio() <= 0.5) pBlendPath = pBlendPathStart; else pBlendPath = pBlendPathEnd; if (pBlendPath->GetOrigMapping() != 0) NodeBlender::ReversePath(pDestCoords,pDestVerbs,m_ArrayLength); } // We need to do some work on the blended path if (!NodeBlender::ProcessBlendedPath(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Closed)) return FALSE; Path RetnPath; RetnPath.Initialise(m_ArrayLength); BOOL Filled = pPathStart->IsFilled || pPathEnd->IsFilled; BOOL Stroked = pPathStart->IsStroked || pPathEnd->IsStroked; RetnPath.MergeTwoPaths(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Filled); pPath->ClearPath(); pPath->CloneFrom(RetnPath); pPath->IsFilled = Filled; pPath->IsStroked = Stroked; return TRUE; }