//----------------------------------------------------------------------------- void GdiplusDrawContext::drawGraphicsPath (CGraphicsPath* _path, PathDrawMode mode, CGraphicsTransform* t) { GdiplusGraphicsPath* gdiPlusPath = dynamic_cast<GdiplusGraphicsPath*> (_path); if (gdiPlusPath && pGraphics) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); Gdiplus::GraphicsPath* path = gdiPlusPath->getGraphicsPath (); if (t) { Gdiplus::Matrix matrix; convert (matrix, *t); path = path->Clone (); path->Transform (&matrix); } if (mode == kPathStroked) { pGraphics->DrawPath (getPen (), path); } else { path->SetFillMode (mode == kPathFilledEvenOdd ? Gdiplus::FillModeAlternate : Gdiplus::FillModeWinding); pGraphics->FillPath (getBrush (), path); } if (path != gdiPlusPath->getGraphicsPath ()) delete path; } }
//----------------------------------------------------------------------------- void GdiplusDrawContext::fillRadialGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& center, CCoord radius, const CPoint& originOffset, bool evenOdd, CGraphicsTransform* t) { #if DEBUG DebugPrint ("WARNING: GdiplusDrawContext::fillRadialGradient is not working as expected ! FIXME\n"); #endif GdiplusGraphicsPath* gdiPlusPath = dynamic_cast<GdiplusGraphicsPath*> (_path); if (gdiPlusPath && pGraphics) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); Gdiplus::GraphicsPath* path = gdiPlusPath->getGraphicsPath (); if (t) { Gdiplus::Matrix matrix; convert (matrix, *t); path = path->Clone (); path->Transform (&matrix); } path->SetFillMode (evenOdd ? Gdiplus::FillModeAlternate : Gdiplus::FillModeWinding); Gdiplus::PointF c1p ((Gdiplus::REAL)(center.x + originOffset.x), (Gdiplus::REAL)(center.y + originOffset.y)); CRect boundingBox = gdiPlusPath->getBoundingBox (); Gdiplus::GraphicsPath brushPath; brushPath.AddEllipse ((Gdiplus::REAL)boundingBox.left, (Gdiplus::REAL)boundingBox.top, (Gdiplus::REAL)boundingBox.getWidth (), (Gdiplus::REAL)boundingBox.getHeight ()); Gdiplus::Matrix graphicsMatrix; pGraphics->GetTransform (&graphicsMatrix); brushPath.Transform (&graphicsMatrix); Gdiplus::PathGradientBrush brush (&brushPath); // set center brush.SetCenterPoint (c1p); // set the colors Gdiplus::Color* colors = new Gdiplus::Color [gradient.getColorStops ().size ()]; Gdiplus::REAL* positions = new Gdiplus::REAL [gradient.getColorStops ().size ()]; uint32_t index = 0; for (CGradient::ColorStopMap::const_iterator it = gradient.getColorStops ().begin (); it != gradient.getColorStops ().end (); ++it, ++index) { CColor color = it->second; color.alpha = (int8_t)((float)color.alpha * currentState.globalAlpha); colors[index] = createGdiPlusColor (color); positions[index] = (Gdiplus::REAL)it->first; } brush.SetCenterColor (colors[0]); INT count = static_cast<INT> (gradient.getColorStops ().size ()) - 1; brush.SetSurroundColors (colors+1, &count); pGraphics->FillPath (&brush, path); if (path != gdiPlusPath->getGraphicsPath ()) delete path; delete [] colors; delete [] positions; } }
//----------------------------------------------------------------------------- CGContextRef CGDrawContext::beginCGContext (bool swapYAxis, bool integralOffset) { if (cgContext) { if (currentState.clipRect.isEmpty ()) return 0; CGContextSaveGState (cgContext); CGRect cgClipRect = CGRectFromCRect (currentState.clipRect); if (integralOffset) cgClipRect = pixelAlligned (cgClipRect); CGContextClipToRect (cgContext, cgClipRect); #if DEBUG if (showClip) { CGContextSetRGBFillColor (cgContext, 1, 0, 0, 0.5); CGContextFillRect (cgContext, cgClipRect); } #endif if (getCurrentTransform ().isInvariant () == false) { CGraphicsTransform t = getCurrentTransform (); if (integralOffset) { CGPoint p = pixelAlligned (CGPointFromCPoint (CPoint (t.dx, t.dy))); t.dx = p.x; t.dy = p.y; } CGContextConcatCTM (cgContext, QuartzGraphicsPath::createCGAffineTransform (t)); } if (!swapYAxis) CGContextScaleCTM (cgContext, 1, -1); return cgContext; } return 0; }
//----------------------------------------------------------------------------- void GdiplusDrawContext::drawLine (const LinePair& line) { if (pGraphics && pPen) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); CPoint p1 (line.first); CPoint p2 (line.second); pGraphics->TranslateTransform (0.5f, 0.5f); pGraphics->DrawLine (pPen, (Gdiplus::REAL)p1.x, (Gdiplus::REAL)p1.y, (Gdiplus::REAL)p2.x, (Gdiplus::REAL)p2.y); pGraphics->TranslateTransform (-0.5f, -0.5f); } }
//----------------------------------------------------------------------------- void GdiplusDrawContext::drawEllipse (const CRect &_rect, const CDrawStyle drawStyle) { if (pGraphics) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); CRect rect (_rect); rect.normalize (); if (pBrush && (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked)) { pGraphics->FillEllipse (pBrush, (Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.getWidth (), (Gdiplus::REAL)rect.getHeight ()); } if (pPen && (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked)) { pGraphics->DrawEllipse (pPen, (Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.getWidth (), (Gdiplus::REAL)rect.getHeight ()); } } }
//----------------------------------------------------------------------------- void GdiplusDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { #if DEBUG DebugPrint ("WARNING: GdiplusDrawContext::fillLinearGradient is not working as expected ! FIXME"); #endif GdiplusGraphicsPath* gdiPlusPath = dynamic_cast<GdiplusGraphicsPath*> (_path); if (gdiPlusPath && pGraphics) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); Gdiplus::GraphicsPath* path = gdiPlusPath->getGraphicsPath (); if (t) { Gdiplus::Matrix matrix; convert (matrix, *t); path = path->Clone (); path->Transform (&matrix); } Gdiplus::Color* colors = new Gdiplus::Color [gradient.getColorStops ().size ()]; Gdiplus::REAL* positions = new Gdiplus::REAL [gradient.getColorStops ().size ()]; uint32_t index = 0; for (CGradient::ColorStopMap::const_iterator it = gradient.getColorStops ().begin (); it != gradient.getColorStops ().end (); ++it, ++index) { CColor color = it->second; color.alpha = (int8_t)((float)color.alpha * currentState.globalAlpha); colors[index] = createGdiPlusColor (color); positions[index] = (Gdiplus::REAL)it->first; } Gdiplus::PointF c1p ((Gdiplus::REAL)(startPoint.x), (Gdiplus::REAL)(startPoint.y)); Gdiplus::PointF c2p ((Gdiplus::REAL)(endPoint.x), (Gdiplus::REAL)(endPoint.y)); Gdiplus::LinearGradientBrush brush (c1p, c2p, colors[0], colors[gradient.getColorStops ().size () - 1]); brush.SetInterpolationColors (colors, positions, static_cast<INT> (gradient.getColorStops ().size ())); path->SetFillMode (evenOdd ? Gdiplus::FillModeAlternate : Gdiplus::FillModeWinding); pGraphics->FillPath (&brush, path); if (path != gdiPlusPath->getGraphicsPath ()) delete path; delete [] colors; delete [] positions; } }
//----------------------------------------------------------------------------- void GdiplusDrawContext::drawArc (const CRect& rect, const float _startAngle, const float _endAngle, const CDrawStyle drawStyle) { if (pGraphics) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); float endAngle = _endAngle; if (endAngle < _startAngle) endAngle += 360.f; endAngle = fabs (endAngle - _startAngle); Gdiplus::RectF r ((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.getWidth (), (Gdiplus::REAL)rect.getHeight ()); Gdiplus::GraphicsPath path; path.AddArc (r, _startAngle, endAngle); if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) pGraphics->FillPath (pBrush, &path); if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) pGraphics->DrawPath (pPen, &path); } }
QPoint GraphicsWidget::pickCell(const QPointF &pos) const { //transform the weird skewed coordinates back to QPointF localPos = getCurrentTransform().inverted().map(pos); int roundedX = qRound(localPos.x()); int roundedY = qRound(localPos.y()); //subtract the square grid cell we're on from the floating point location float compX = localPos.x() - roundedX; float compY = localPos.y() - roundedY; //if the point is inside the hexagon then we know it would have been inside the hexagon when it was unskewed if (sign(compX) == sign(compY) || DISPLAY_HEXAGON.containsPoint(QPointF(compX, compY), Qt::OddEvenFill)) { return QPoint(roundedX, roundedY); } else { //we can tell if the correct hexagon is above, below, left, or right purely by comparing compX and compY //if compX + compY is greater than zero, we know it must be y+1 or x+1 if (compX + compY > 0) { //if compY is greater than compX, it is y+1 if (compY > compX) return QPoint(roundedX, roundedY + 1); else return QPoint(roundedX + 1, roundedY); } else { //it must be y-1 or x-1 //if compY is less than compX, it must be y-1 if (compY < compX) return QPoint(roundedX, roundedY - 1); else return QPoint(roundedX - 1, roundedY); } } }
//----------------------------------------------------------------------------- void D2DDrawContext::drawBitmap (CBitmap* bitmap, const CRect& dest, const CPoint& offset, float alpha) { if (renderTarget == 0) return; D2DApplyClip ac (this); if (ac.isEmpty ()) return; double transformedScaleFactor = getScaleFactor (); CGraphicsTransform t = getCurrentTransform (); if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0) transformedScaleFactor *= t.m11; IPlatformBitmap* platformBitmap = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor); D2DBitmap* d2dBitmap = platformBitmap ? dynamic_cast<D2DBitmap*> (platformBitmap) : 0; if (d2dBitmap) { if (d2dBitmap->getSource ()) { ID2D1Bitmap* d2d1Bitmap = D2DBitmapCache::instance ()->getBitmap (d2dBitmap, renderTarget); if (d2d1Bitmap) { double bitmapScaleFactor = platformBitmap->getScaleFactor (); CGraphicsTransform bitmapTransform; bitmapTransform.scale (bitmapScaleFactor, bitmapScaleFactor); Transform transform (*this, bitmapTransform.inverse ()); CRect d (dest); d.makeIntegral (); CRect source (dest); source.offset (-source.left, -source.top); source.offset (offset.x, offset.y); bitmapTransform.transform (source); D2D1_RECT_F sourceRect = makeD2DRect (source); renderTarget->DrawBitmap (d2d1Bitmap, makeD2DRect (d), alpha * currentState.globalAlpha, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, &sourceRect); } } } }
//----------------------------------------------------------------------------- void GdiplusDrawContext::drawRect (const CRect &_rect, const CDrawStyle drawStyle) { if (pGraphics) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); CRect rect (_rect); rect.normalize (); if (pBrush && (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked)) { Gdiplus::RectF r ((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.getWidth (), (Gdiplus::REAL)rect.getHeight ()); pGraphics->FillRectangle (pBrush, r); } if (pPen && (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked)) { Gdiplus::RectF r ((Gdiplus::REAL)rect.left, (Gdiplus::REAL)rect.top, (Gdiplus::REAL)rect.getWidth () - 1, (Gdiplus::REAL)rect.getHeight () - 1); pGraphics->TranslateTransform (0.5f, 0.5f); pGraphics->DrawRectangle (pPen, r); pGraphics->TranslateTransform (-0.5f, -0.5f); } } }
//----------------------------------------------------------------------------- void CGDrawContext::drawBitmap (CBitmap* bitmap, const CRect& inRect, const CPoint& inOffset, float alpha) { if (bitmap == 0 || alpha == 0.f) return; double transformedScaleFactor = scaleFactor; CGraphicsTransform t = getCurrentTransform (); if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0) transformedScaleFactor *= t.m11; IPlatformBitmap* platformBitmap = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor); CGBitmap* cgBitmap = platformBitmap ? dynamic_cast<CGBitmap*> (platformBitmap) : 0; CGImageRef image = cgBitmap ? cgBitmap->getCGImage () : 0; if (image) { CGContextRef context = beginCGContext (false, true); if (context) { CGLayerRef layer = cgBitmap->getCGLayer (); if (layer == 0) { BitmapDrawCountMap::iterator it = bitmapDrawCount.find (cgBitmap); if (it == bitmapDrawCount.end ()) { bitmapDrawCount.insert (std::pair<CGBitmap*, int32_t> (cgBitmap, 1)); } else { it->second++; layer = cgBitmap->createCGLayer (context); } } drawCGImageRef (context, image, layer, cgBitmap->getScaleFactor (), inRect, inOffset, alpha, bitmap); releaseCGContext (context); } } }
//----------------------------------------------------------------------------- void GdiplusDrawContext::drawPolygon (const PointList& polygonPointList, const CDrawStyle drawStyle) { if (polygonPointList.size () == 0) return; GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); Gdiplus::PointF points[30]; Gdiplus::PointF* polyPoints; bool allocated = false; if (polygonPointList.size () > 30) { polyPoints = new Gdiplus::PointF[polygonPointList.size ()]; allocated = true; } else polyPoints = points; for (uint32_t i = 0; i < polygonPointList.size (); i++) { polyPoints[i].X = (Gdiplus::REAL)(polygonPointList[i].x); polyPoints[i].Y = (Gdiplus::REAL)(polygonPointList[i].y); } if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) pGraphics->FillPolygon (pBrush, polyPoints, static_cast<INT> (polygonPointList.size ())); if (drawStyle == kDrawFilledAndStroked || drawStyle == kDrawStroked) { pGraphics->TranslateTransform (0.5f, 0.5f); pGraphics->DrawPolygon (pPen, polyPoints, static_cast<INT> (polygonPointList.size ())); pGraphics->TranslateTransform (-0.5f, -0.5f); } if (allocated) delete[] polyPoints; }
void GraphicsWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event) //set up painting with antialiasing etc QPainter painter; painter.begin(&elements); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); //transform coordinates to fit everything neatly on the screen painter.save(); painter.setWorldTransform(getCurrentTransform()); if (grid != nullptr) { //loop through and draw each entry for (const auto& cell: grid->getCells()) { GridEntry &entry = grid->getEntry(cell); if (entry.modified) { entry.modified = false; painter.save(); painter.translate(cell.x(), cell.y()); QPen pen(Qt::black); pen.setWidthF(0); painter.setPen(pen); if (entry.type == GridEntry::Wall) painter.setBrush(Qt::darkBlue); else if (entry.type == GridEntry::Start) painter.setBrush(Qt::yellow); else if (entry.type == GridEntry::End) painter.setBrush(Qt::red); else if (entry.path) painter.setBrush(Qt::white); else if (entry.searched) painter.setBrush(Qt::cyan); else painter.setBrush(Qt::darkGreen); painter.drawConvexPolygon(DISPLAY_HEXAGON); painter.restore(); } } } painter.restore(); painter.setPen(Qt::white); QPainter screenPainter(this); screenPainter.fillRect(rect(), QBrush(Qt::black)); screenPainter.drawImage(0, 0, elements); }
//----------------------------------------------------------------------------- void GdiplusDrawContext::drawBitmap (CBitmap* cbitmap, const CRect& dest, const CPoint& offset, float alpha) { alpha *= currentState.globalAlpha; if (alpha == 0.f || pGraphics == 0) return; IPlatformBitmap* platformBitmap = cbitmap ? cbitmap->getPlatformBitmap () : 0; GdiplusBitmap* gpb = platformBitmap ? dynamic_cast<GdiplusBitmap*> (platformBitmap) : 0; Gdiplus::Bitmap* bitmap = gpb ? gpb->getBitmap () : 0; if (bitmap) { GdiplusDrawScope drawScope (pGraphics, currentState.clipRect, getCurrentTransform ()); Gdiplus::ImageAttributes imageAtt; if (alpha != 1.f) { // introducing the alpha blend matrix Gdiplus::ColorMatrix colorMatrix = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, alpha, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; // create the imageattribute modifier imageAtt.SetColorMatrix (&colorMatrix, Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap); #if 1 Gdiplus::Rect myDestRect( (INT)dest.left, (INT)dest.top, (INT)dest.getWidth (), (INT)dest.getHeight ()); pGraphics->DrawImage ( bitmap, myDestRect, (INT)offset.x, (INT)offset.y, (INT)dest.getWidth (), (INT)dest.getHeight (), Gdiplus::UnitPixel, &imageAtt); #else // create a temporary bitmap to prevent OutOfMemory errors Gdiplus::Bitmap myBitmapBuffer ((INT)dest.getWidth (), (INT)dest.getHeight (),PixelFormat32bppARGB); // create a graphics context for the temporary bitmap Gdiplus::Graphics* myGraphicsBuffer = Gdiplus::Graphics::FromImage (&myBitmapBuffer); // copy the rectangle we want to paint to the temporary bitmap Gdiplus::Rect myTransRect( 0, 0, (INT)dest.getWidth (), (INT)dest.getHeight ()); // transfer the bitmap (without modification by imageattr!) myGraphicsBuffer->DrawImage ( bitmap,myTransRect, (INT)offset.x, (INT)offset.y, (INT)dest.getWidth (), (INT)dest.getHeight (), Gdiplus::UnitPixel, 0); // now transfer the temporary to the real context at the advised location Gdiplus::Rect myDestRect ( (INT)dest.left, (INT)dest.top, (INT)dest.getWidth (), (INT)dest.getHeight ()); // transfer from temporary bitmap to real context (with imageattr) pGraphics->DrawImage ( &myBitmapBuffer, myDestRect, (INT)0, (INT)0, (INT)dest.getWidth (), (INT)dest.getHeight (), Gdiplus::UnitPixel, &imageAtt); // delete the temporary context of the temporary bitmap delete myGraphicsBuffer; #endif } else { Gdiplus::Rect myDestRect( (INT)dest.left, (INT)dest.top, (INT)dest.getWidth (), (INT)dest.getHeight ()); pGraphics->DrawImage ( bitmap, myDestRect, (INT)offset.x, (INT)offset.y, (INT)dest.getWidth (), (INT)dest.getHeight (), Gdiplus::UnitPixel, 0); } } }
//----------------------------------------------------------------------------- void CDrawContext::setClipRect (const CRect &clip) { currentState.clipRect = clip; getCurrentTransform ().transform (currentState.clipRect); }
//----------------------------------------------------------------------------- CRect& CDrawContext::getClipRect (CRect &clip) const { clip = currentState.clipRect; getCurrentTransform ().inverse ().transform (clip); return clip; }