4 #include "IGraphicsSkia.h" 6 #pragma warning( push ) 7 #pragma warning( disable : 4244 ) 8 #include "SkDashPathEffect.h" 9 #include "SkGradientShader.h" 10 #include "SkMaskFilter.h" 12 #include "SkFontMetrics.h" 13 #include "SkTypeface.h" 14 #include "SkVertices.h" 15 #include "SkSwizzle.h" 16 #pragma warning( pop ) 18 #if defined OS_MAC || defined OS_IOS 19 #include "SkCGUtils.h" 20 #if defined IGRAPHICS_GL2 21 #include <OpenGL/gl.h> 22 #elif defined IGRAPHICS_GL3 23 #include <OpenGL/gl3.h> 24 #elif defined IGRAPHICS_METAL 26 #import <Metal/Metal.h> 27 #import <QuartzCore/CAMetalLayer.h> 28 #elif !defined IGRAPHICS_CPU 29 #error Define either IGRAPHICS_GL2, IGRAPHICS_GL3, IGRAPHICS_METAL, or IGRAPHICS_CPU for IGRAPHICS_SKIA with OS_MAC 32 #pragma comment(lib, "libpng.lib") 33 #pragma comment(lib, "zlib.lib") 34 #pragma comment(lib, "skia.lib") 35 #pragma comment(lib, "svg.lib") 36 #pragma comment(lib, "opengl32.lib") 39 #if defined IGRAPHICS_GL 40 #include "gl/GrGLInterface.h" 43 using namespace iplug;
44 using namespace igraphics;
46 extern std::map<std::string, MTLTexturePtr> gTextureMap;
48 #pragma mark - Private Classes and Structs 53 Bitmap(sk_sp<SkSurface> surface,
int width,
int height,
int scale,
float drawScale);
54 Bitmap(
const char* path,
double sourceScale);
55 Bitmap(
const void* pData,
int size,
double sourceScale);
56 Bitmap(sk_sp<SkImage>,
double sourceScale);
59 SkiaDrawable mDrawable;
62 IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkSurface> surface,
int width,
int height,
int scale,
float drawScale)
64 mDrawable.mSurface = surface;
65 mDrawable.mIsSurface =
true;
67 SetBitmap(&mDrawable, width, height, scale, drawScale);
70 IGraphicsSkia::Bitmap::Bitmap(
const char* path,
double sourceScale)
72 sk_sp<SkData> data = SkData::MakeFromFileName(path);
74 assert(data &&
"Unable to load file at path");
76 mDrawable.mImage = SkImage::MakeFromEncoded(data);
78 mDrawable.mIsSurface =
false;
79 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
82 IGraphicsSkia::Bitmap::Bitmap(
const void* pData,
int size,
double sourceScale)
84 auto data = SkData::MakeWithoutCopy(pData, size);
85 mDrawable.mImage = SkImage::MakeFromEncoded(data);
87 mDrawable.mIsSurface =
false;
88 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
91 IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkImage> image,
double sourceScale)
93 mDrawable.mImage = image;
94 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
97 struct IGraphicsSkia::Font
99 Font(IFontDataPtr&& data, sk_sp<SkTypeface> typeFace)
100 : mData(std::move(data)), mTypeface(typeFace) {}
103 sk_sp<SkTypeface> mTypeface;
107 StaticStorage<IGraphicsSkia::Font> IGraphicsSkia::sFontCache;
109 #pragma mark - Utility conversions 111 BEGIN_IPLUG_NAMESPACE
112 BEGIN_IGRAPHICS_NAMESPACE
114 SkColor SkiaColor(
const IColor& color,
const IBlend* pBlend)
117 return SkColorSetARGB(
Clip(static_cast<int>(pBlend->mWeight * color.A), 0, 255), color.R, color.G, color.B);
119 return SkColorSetARGB(color.A, color.R, color.G, color.B);
122 SkRect SkiaRect(
const IRECT& r)
124 return SkRect::MakeLTRB(r.
L, r.
T, r.
R, r.
B);
127 SkBlendMode SkiaBlendMode(
const IBlend* pBlend)
130 return SkBlendMode::kSrcOver;
132 switch (pBlend->mMethod)
134 case EBlend::SrcOver:
return SkBlendMode::kSrcOver;
135 case EBlend::SrcIn:
return SkBlendMode::kSrcIn;
136 case EBlend::SrcOut:
return SkBlendMode::kSrcOut;
137 case EBlend::SrcAtop:
return SkBlendMode::kSrcATop;
138 case EBlend::DstOver:
return SkBlendMode::kDstOver;
139 case EBlend::DstIn:
return SkBlendMode::kDstIn;
140 case EBlend::DstOut:
return SkBlendMode::kDstOut;
141 case EBlend::DstAtop:
return SkBlendMode::kDstATop;
142 case EBlend::Add:
return SkBlendMode::kPlus;
143 case EBlend::XOR:
return SkBlendMode::kXor;
146 return SkBlendMode::kClear;
149 SkTileMode SkiaTileMode(
const IPattern& pattern)
151 switch (pattern.mExtend)
153 case EPatternExtend::None:
return SkTileMode::kDecal;
154 case EPatternExtend::Reflect:
return SkTileMode::kMirror;
155 case EPatternExtend::Repeat:
return SkTileMode::kRepeat;
156 case EPatternExtend::Pad:
return SkTileMode::kClamp;
159 return SkTileMode::kClamp;
165 paint.setAntiAlias(
true);
166 paint.setBlendMode(SkiaBlendMode(pBlend));
167 int numStops = pattern.
NStops();
169 if (pattern.mType == EPatternType::Solid || numStops < 2)
171 paint.setColor(SkiaColor(pattern.
GetStop(0).mColor, pBlend));
180 IMatrix m = pattern.mTransform;
187 SkPoint::Make(x1, y1),
188 SkPoint::Make(x2, y2)
192 SkScalar positions[8];
194 assert(numStops <= 8);
196 for(
int i = 0; i < numStops; i++)
199 colors[i] = SkiaColor(stop.mColor, pBlend);
200 positions[i] = stop.mOffset;
203 switch (pattern.mType)
205 case EPatternType::Linear:
206 paint.setShader(SkGradientShader::MakeLinear(points, colors, positions, numStops, SkiaTileMode(pattern), 0,
nullptr));
209 case EPatternType::Radial:
211 float xd = points[0].x() - points[1].x();
212 float yd = points[0].y() - points[1].y();
213 float radius = std::sqrt(xd * xd + yd * yd);
214 paint.setShader(SkGradientShader::MakeRadial(points[0], radius, colors, positions, numStops, SkiaTileMode(pattern), 0,
nullptr));
218 case EPatternType::Sweep:
220 SkMatrix matrix = SkMatrix::MakeAll(m.mXX, m.mYX, 0, m.mXY, m.mYY, 0, 0, 0, 1);
222 paint.setShader(SkGradientShader::MakeSweep(x1, y1, colors,
nullptr, numStops, SkTileMode::kDecal,
223 0, 360 * positions[numStops - 1], 0, &matrix));
236 END_IGRAPHICS_NAMESPACE
241 IGraphicsSkia::IGraphicsSkia(
IGEditorDelegate& dlg,
int w,
int h,
int fps,
float scale)
244 mMainPath.setIsVolatile(
true);
246 #if defined IGRAPHICS_CPU 247 DBGMSG(
"IGraphics Skia CPU @ %i FPS\n", fps);
248 #elif defined IGRAPHICS_METAL 249 DBGMSG(
"IGraphics Skia METAL @ %i FPS\n", fps);
250 #elif defined IGRAPHICS_GL 251 DBGMSG(
"IGraphics Skia GL @ %i FPS\n", fps);
253 StaticStorage<Font>::Accessor storage(sFontCache);
257 IGraphicsSkia::~IGraphicsSkia()
259 StaticStorage<Font>::Accessor storage(sFontCache);
267 return (strstr(extLower,
"png") !=
nullptr) || (strstr(extLower,
"jpg") !=
nullptr) || (strstr(extLower,
"jpeg") !=
nullptr);
290 if (location == EResourceLocation::kWinBinary)
293 const void* pData =
LoadWinResource(fileNameOrResID, ext, size, GetWinModuleHandle());
294 return new Bitmap(pData, size, scale);
298 return new Bitmap(fileNameOrResID, scale);
303 return new Bitmap(pData, dataSize, scale);
308 #if defined IGRAPHICS_GL 309 auto glInterface = GrGLMakeNativeInterface();
310 mGrContext = GrDirectContext::MakeGL(glInterface);
311 #elif defined IGRAPHICS_METAL 312 CAMetalLayer* pMTLLayer = (CAMetalLayer*) pContext;
313 id<MTLDevice> device = pMTLLayer.device;
314 id<MTLCommandQueue> commandQueue = [device newCommandQueue];
315 mGrContext = GrDirectContext::MakeMetal((
void*) device, (
void*) commandQueue);
316 mMTLDevice = (
void*) device;
317 mMTLCommandQueue = (
void*) commandQueue;
318 mMTLLayer = pContext;
328 #if defined IGRAPHICS_GL 330 mScreenSurface =
nullptr;
331 mGrContext =
nullptr;
332 #elif defined IGRAPHICS_METAL 333 [(id<MTLCommandQueue>) mMTLCommandQueue release];
334 mMTLCommandQueue =
nullptr;
336 mMTLDevice =
nullptr;
342 auto w =
static_cast<int>(std::ceil(static_cast<float>(WindowWidth()) * GetScreenScale()));
343 auto h =
static_cast<int>(std::ceil(static_cast<float>(WindowHeight()) * GetScreenScale()));
345 #if defined IGRAPHICS_GL || defined IGRAPHICS_METAL 346 if (mGrContext.get())
348 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
349 mSurface = SkSurface::MakeRenderTarget(mGrContext.get(), SkBudgeted::kYes, info);
355 const size_t bmpSize =
sizeof(BITMAPINFOHEADER) + (w * h *
sizeof(uint32_t));
356 mSurfaceMemory.Resize(bmpSize);
357 BITMAPINFO* bmpInfo =
reinterpret_cast<BITMAPINFO*
>(mSurfaceMemory.Get());
358 ZeroMemory(bmpInfo,
sizeof(BITMAPINFO));
359 bmpInfo->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
360 bmpInfo->bmiHeader.biWidth = w;
361 bmpInfo->bmiHeader.biHeight = -h;
362 bmpInfo->bmiHeader.biPlanes = 1;
363 bmpInfo->bmiHeader.biBitCount = 32;
364 bmpInfo->bmiHeader.biCompression = BI_RGB;
365 void* pixels = bmpInfo->bmiColors;
367 SkImageInfo info = SkImageInfo::Make(w, h, kN32_SkColorType, kPremul_SkAlphaType,
nullptr);
368 mSurface = SkSurface::MakeRasterDirect(info, pixels,
sizeof(uint32_t) * w);
370 mSurface = SkSurface::MakeRasterN32Premul(w, h);
375 mCanvas = mSurface->getCanvas();
382 #if defined IGRAPHICS_GL 383 if (mGrContext.get())
385 int width = WindowWidth() * GetScreenScale();
386 int height = WindowHeight() * GetScreenScale();
389 int fbo = 0, samples = 0, stencilBits = 0;
390 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
391 glGetIntegerv(GL_SAMPLES, &samples);
393 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencilBits);
395 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
398 GrGLFramebufferInfo fbinfo;
400 fbinfo.fFormat = 0x8058;
402 GrBackendRenderTarget backendRT(width, height, samples, stencilBits, fbinfo);
404 mScreenSurface = SkSurface::MakeFromBackendRenderTarget(mGrContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
nullptr,
nullptr);
405 assert(mScreenSurface);
407 #elif defined IGRAPHICS_METAL 408 if (mGrContext.get())
410 int width = WindowWidth() * GetScreenScale();
411 int height = WindowHeight() * GetScreenScale();
413 id<CAMetalDrawable> drawable = [(CAMetalLayer*) mMTLLayer nextDrawable];
415 GrMtlTextureInfo fbInfo;
416 fbInfo.fTexture.retain((
const void*)(drawable.texture));
417 GrBackendRenderTarget backendRT(width, height, 1 , fbInfo);
419 mScreenSurface = SkSurface::MakeFromBackendRenderTarget(mGrContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType,
nullptr,
nullptr);
421 mMTLDrawable = (
void*) drawable;
422 assert(mScreenSurface);
429 void IGraphicsSkia::DrawImGui(SkSurface* surface)
431 #if defined IGRAPHICS_IMGUI 437 const ImDrawData* drawData = ImGui::GetDrawData();
438 SkTDArray<SkPoint> pos;
439 SkTDArray<SkPoint> uv;
440 SkTDArray<SkColor> color;
442 auto canvas = surface->getCanvas();
444 for (
int i = 0; i < drawData->CmdListsCount; ++i) {
445 const ImDrawList* drawList = drawData->CmdLists[i];
448 pos.rewind(); uv.rewind(); color.rewind();
449 for (
int j = 0; j < drawList->VtxBuffer.size(); ++j) {
450 const ImDrawVert& vert = drawList->VtxBuffer[j];
451 pos.push_back(SkPoint::Make(vert.pos.x * GetScreenScale(), vert.pos.y * GetScreenScale()));
452 uv.push_back(SkPoint::Make(vert.uv.x, vert.uv.y));
453 color.push_back(vert.col);
456 SkSwapRB(color.begin(), color.begin(), color.count());
461 for (
int j = 0; j < drawList->CmdBuffer.size(); ++j)
463 const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j];
465 SkAutoCanvasRestore acr(canvas,
true);
468 if (drawCmd->UserCallback)
470 drawCmd->UserCallback(drawList, drawCmd);
474 SkPaint* paint =
static_cast<SkPaint*
>(drawCmd->TextureId);
477 canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x * GetScreenScale(),
478 drawCmd->ClipRect.y * GetScreenScale(),
479 drawCmd->ClipRect.z * GetScreenScale(),
480 drawCmd->ClipRect.w * GetScreenScale()));
482 auto vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
483 drawList->VtxBuffer.size(),
484 pos.begin(), uv.begin(), color.begin(),
486 drawList->IdxBuffer.begin() + indexOffset);
488 canvas->drawVertices(vertices, SkBlendMode::kModulate, mImGuiRenderer->fFontPaint);
490 indexOffset += drawCmd->ElemCount;
500 #if defined OS_MAC || defined OS_IOS 502 mSurface->peekPixels(&pixmap);
504 bmp.installPixels(pixmap);
505 CGContext* pCGContext = (CGContextRef) GetPlatformContext();
506 CGContextSaveGState(pCGContext);
507 CGContextScaleCTM(pCGContext, 1.0 / GetScreenScale(), 1.0 / GetScreenScale());
508 SkCGDrawBitmap(pCGContext, bmp, 0, 0);
509 CGContextRestoreGState(pCGContext);
511 auto w = WindowWidth() * GetScreenScale();
512 auto h = WindowHeight() * GetScreenScale();
513 BITMAPINFO* bmpInfo =
reinterpret_cast<BITMAPINFO*
>(mSurfaceMemory.Get());
514 HWND hWnd = (HWND) GetWindow();
516 HDC hdc = BeginPaint(hWnd, &ps);
517 StretchDIBits(hdc, 0, 0, w, h, 0, 0, w, h, bmpInfo->bmiColors, bmpInfo, DIB_RGB_COLORS, SRCCOPY);
518 ReleaseDC(hWnd, hdc);
521 #error NOT IMPLEMENTED 524 mSurface->draw(mScreenSurface->getCanvas(), 0.0, 0.0,
nullptr);
526 #if defined IGRAPHICS_IMGUI && !IGRAPHICS_CPU 529 mImGuiRenderer->NewFrame();
530 DrawImGui(mScreenSurface.get());
534 mScreenSurface->getCanvas()->flush();
536 #ifdef IGRAPHICS_METAL 537 id<MTLCommandBuffer> commandBuffer = [(id<MTLCommandQueue>) mMTLCommandQueue commandBuffer];
538 commandBuffer.label =
@"Present";
540 [commandBuffer presentDrawable:(id<CAMetalDrawable>) mMTLDrawable];
541 [commandBuffer commit];
550 p.setFilterQuality(kHigh_SkFilterQuality);
551 p.setAntiAlias(
true);
552 p.setBlendMode(SkiaBlendMode(pBlend));
554 p.setAlpha(
Clip(static_cast<int>(pBlend->mWeight * 255), 0, 255));
562 mCanvas->clipRect(SkiaRect(dest));
563 mCanvas->translate(dest.
L, dest.
T);
564 mCanvas->scale(scale1, scale1);
565 mCanvas->translate(-srcX * scale2, -srcY * scale2);
567 if (image->mIsSurface)
568 image->mSurface->draw(mCanvas, 0.0, 0.0, &p);
570 mCanvas->drawImage(image->mImage, 0.0, 0.0, &p);
578 arc.setIsVolatile(
true);
580 float sweep = (a2 - a1);
582 if (sweep >= 360.f || sweep <= -360.f)
584 arc.addCircle(cx, cy, r);
585 mMainPath.addPath(arc, mMatrix, SkPath::kAppend_AddPathMode);
589 if (winding == EWinding::CW)
600 arc.arcTo(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, sweep,
false);
601 mMainPath.addPath(arc, mMatrix, SkPath::kExtend_AddPathMode);
608 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
609 mCanvas->readPixels(bitmap, x, y);
610 auto color = bitmap.getColor(0,0);
611 return IColor(SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
616 StaticStorage<Font>::Accessor storage(sFontCache);
617 Font* cached = storage.Find(fontID);
622 IFontDataPtr data = font->GetFontData();
626 auto wrappedData = SkData::MakeWithoutCopy(data->Get(), data->GetSize());
627 int index = data->GetFaceIdx();
628 auto typeface = SkTypeface::MakeFromData(wrappedData, index);
632 storage.Add(
new Font(std::move(data), typeface), fontID);
640 void IGraphicsSkia::PrepareAndMeasureText(
const IText& text,
const char* str,
IRECT& r,
double& x,
double & y, SkFont& font)
const 642 SkFontMetrics metrics;
646 StaticStorage<Font>::Accessor storage(sFontCache);
647 Font* pFont = storage.Find(text.mFont);
649 assert(pFont &&
"No font found - did you forget to load it?");
651 font.setTypeface(pFont->mTypeface);
652 font.setHinting(SkFontHinting::kSlight);
653 font.setForceAutoHinting(
false);
654 font.setSubpixel(
true);
655 font.setSize(text.mSize * pFont->mData->GetHeightEMRatio());
658 const double textWidth = font.measureText(str, strlen(str), SkTextEncoding::kUTF8,
nullptr);
659 font.getMetrics(&metrics);
661 const double textHeight = text.mSize;
662 const double ascender = metrics.fAscent;
663 const double descender = metrics.fDescent;
667 case EAlign::Near: x = r.
L;
break;
668 case EAlign::Center: x = r.
MW() - (textWidth / 2.0);
break;
669 case EAlign::Far: x = r.
R - textWidth;
break;
672 switch (text.mVAlign)
674 case EVAlign::Top: y = r.
T - ascender;
break;
675 case EVAlign::Middle: y = r.
MH() - descender + (textHeight / 2.0);
break;
676 case EVAlign::Bottom: y = r.
B - descender;
break;
679 r =
IRECT((
float) x, (
float) y + ascender, (
float) (x + textWidth), (
float) (y + ascender + textHeight));
685 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
689 PrepareAndMeasureText(text, str, bounds, x, y, font);
690 DoMeasureTextRotation(text, r, bounds);
696 IRECT measured = bounds;
699 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
703 PrepareAndMeasureText(text, str, measured, x, y, font);
705 DoTextRotation(text, bounds, measured);
707 paint.setColor(SkiaColor(text.mFGColor, pBlend));
708 mCanvas->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint);
709 PathTransformRestore();
714 SkPaint paint = SkiaPaint(pattern, pBlend);
715 paint.setStyle(SkPaint::kStroke_Style);
717 switch (options.mCapOption)
719 case ELineCap::Butt: paint.setStrokeCap(SkPaint::kButt_Cap);
break;
720 case ELineCap::Round: paint.setStrokeCap(SkPaint::kRound_Cap);
break;
721 case ELineCap::Square: paint.setStrokeCap(SkPaint::kSquare_Cap);
break;
724 switch (options.mJoinOption)
726 case ELineJoin::Miter: paint.setStrokeJoin(SkPaint::kMiter_Join);
break;
727 case ELineJoin::Round: paint.setStrokeJoin(SkPaint::kRound_Join);
break;
728 case ELineJoin::Bevel: paint.setStrokeJoin(SkPaint::kBevel_Join);
break;
731 if (options.mDash.GetCount())
734 int dashCount = options.mDash.GetCount();
735 int dashMax = dashCount & 1 ? dashCount * 2 : dashCount;
738 for (
int i = 0; i < dashMax; i += 2)
740 dashArray[i + 0] = options.mDash.GetArray()[i % dashCount];
741 dashArray[i + 1] = options.mDash.GetArray()[(i + 1) % dashCount];
744 paint.setPathEffect(SkDashPathEffect::Make(dashArray, dashMax, options.mDash.GetOffset()));
747 paint.setStrokeWidth(thickness);
748 paint.setStrokeMiter(options.mMiterLimit);
752 if (!options.mPreserve)
758 SkPaint paint = SkiaPaint(pattern, pBlend);
759 paint.setStyle(SkPaint::kFill_Style);
761 if (options.mFillRule == EFillRule::Winding)
762 mMainPath.setFillType(SkPathFillType::kWinding);
764 mMainPath.setFillType(SkPathFillType::kEvenOdd);
768 if (!options.mPreserve)
772 #ifdef IGRAPHICS_DRAWFILL_DIRECT 775 auto paint = SkiaPaint(color, pBlend);
776 paint.setStyle(SkPaint::Style::kStroke_Style);
777 paint.setStrokeWidth(thickness);
778 mCanvas->drawRect(SkiaRect(bounds), paint);
783 auto paint = SkiaPaint(color, pBlend);
784 paint.setStyle(SkPaint::Style::kStroke_Style);
785 paint.setStrokeWidth(thickness);
786 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
791 auto paint = SkiaPaint(color, pBlend);
792 paint.setStyle(SkPaint::Style::kStroke_Style);
793 paint.setStrokeWidth(thickness);
794 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1),
false, paint);
799 auto paint = SkiaPaint(color, pBlend);
800 paint.setStyle(SkPaint::Style::kStroke_Style);
801 paint.setStrokeWidth(thickness);
802 mCanvas->drawCircle(cx, cy, r, paint);
807 auto paint = SkiaPaint(color, pBlend);
808 paint.setStyle(SkPaint::Style::kStroke_Style);
809 paint.setStrokeWidth(thickness);
810 mCanvas->drawOval(SkiaRect(bounds), paint);
815 auto paint = SkiaPaint(color, pBlend);
816 paint.setStyle(SkPaint::Style::kFill_Style);
817 mCanvas->drawRect(SkiaRect(bounds), paint);
822 auto paint = SkiaPaint(color, pBlend);
823 paint.setStyle(SkPaint::Style::kFill_Style);
824 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
829 auto paint = SkiaPaint(color, pBlend);
830 paint.setStyle(SkPaint::Style::kFill_Style);
831 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1),
true, paint);
836 auto paint = SkiaPaint(color, pBlend);
837 paint.setStyle(SkPaint::Style::kFill_Style);
838 mCanvas->drawCircle(cx, cy, r, paint);
843 auto paint = SkiaPaint(color, pBlend);
844 paint.setStyle(SkPaint::Style::kFill_Style);
845 mCanvas->drawOval(SkiaRect(bounds), paint);
849 void IGraphicsSkia::RenderPath(SkPaint& paint)
853 if (!mMatrix.isIdentity() && mMatrix.invert(&invMatrix))
856 path.setIsVolatile(
true);
857 mMainPath.transform(invMatrix, &path);
858 mCanvas->drawPath(path, paint);
862 mCanvas->drawPath(mMainPath, paint);
866 void IGraphicsSkia::PathTransformSetMatrix(
const IMatrix& m)
868 double xTranslate = 0.0;
869 double yTranslate = 0.0;
874 if (!mLayers.empty())
876 IRECT bounds = mLayers.top()->Bounds();
878 xTranslate = -bounds.
L;
879 yTranslate = -bounds.
T;
882 mMatrix = SkMatrix::MakeAll(m.mXX, m.mXY, m.mTX, m.mYX, m.mYY, m.mTY, 0, 0, 1);
883 auto scale = GetTotalScale();
884 SkMatrix globalMatrix = SkMatrix::Scale(scale, scale);
885 mClipMatrix = SkMatrix();
886 mFinalMatrix = mMatrix;
887 globalMatrix.preTranslate(xTranslate, yTranslate);
888 mClipMatrix.postConcat(globalMatrix);
889 mFinalMatrix.postConcat(globalMatrix);
890 mCanvas->setMatrix(mFinalMatrix);
893 void IGraphicsSkia::SetClipRegion(
const IRECT& r)
895 mCanvas->restoreToCount(0);
897 mCanvas->setMatrix(mClipMatrix);
898 mCanvas->clipRect(SkiaRect(r));
899 mCanvas->setMatrix(mFinalMatrix);
904 sk_sp<SkSurface> surface;
906 #ifndef IGRAPHICS_CPU 907 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
910 surface = SkSurface::MakeRasterN32Premul(width, height);
914 surface = SkSurface::MakeRenderTarget(mGrContext.get(), SkBudgeted::kYes, info);
917 surface = SkSurface::MakeRasterN32Premul(width, height);
920 surface->getCanvas()->save();
922 return new Bitmap(std::move(surface), width, height, scale, drawScale);
927 mCanvas = mLayers.empty() ? mSurface->getCanvas() : mLayers.top()->GetAPIBitmap()->GetBitmap()->mSurface->getCanvas();
930 static size_t CalcRowBytes(
int width)
932 width = ((width + 7) & (-8));
933 return width *
sizeof(uint32_t);
938 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
939 size_t rowBytes = CalcRowBytes(pDrawable->mSurface->width());
940 int size = pDrawable->mSurface->height() *
static_cast<int>(rowBytes);
944 if (data.GetSize() >= size)
946 SkImageInfo info = SkImageInfo::MakeN32Premul(pDrawable->mSurface->width(), pDrawable->mSurface->height());
947 pDrawable->mSurface->readPixels(info, data.Get(), rowBytes, 0, 0);
953 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
954 int width = pDrawable->mSurface->width();
955 int height = pDrawable->mSurface->height();
956 size_t rowBytes = CalcRowBytes(width);
957 double scale = layer->GetAPIBitmap()->GetDrawScale() * layer->GetAPIBitmap()->GetScale();
959 SkCanvas* pCanvas = pDrawable->mSurface->getCanvas();
964 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
965 SkPixmap pixMap(info, mask.Get(), rowBytes);
966 sk_sp<SkImage> image = SkImage::MakeFromRaster(pixMap,
nullptr,
nullptr);
967 sk_sp<SkImage> foreground;
971 if (shadow.mDrawForeground)
972 foreground = pDrawable->mSurface->makeImageSnapshot();
974 pCanvas->clear(SK_ColorTRANSPARENT);
976 IBlend blend(EBlend::Default, shadow.mOpacity);
977 pCanvas->setMatrix(m);
978 pCanvas->drawImage(image.get(), shadow.mXOffset * scale, shadow.mYOffset * scale);
979 m = SkMatrix::Scale(scale, scale);
980 pCanvas->setMatrix(m);
981 pCanvas->translate(-layer->Bounds().L, -layer->Bounds().T);
982 SkPaint p = SkiaPaint(shadow.mPattern, &blend);
983 p.setBlendMode(SkBlendMode::kSrcIn);
984 pCanvas->drawPaint(p);
986 if (shadow.mDrawForeground)
989 pCanvas->setMatrix(m);
990 pCanvas->drawImage(foreground.get(), 0.0, 0.0);
996 SkRect r = SkiaRect(innerBounds.
GetTranslated(xyDrop, xyDrop));
998 SkPaint paint = SkiaPaint(COLOR_BLACK_DROP_SHADOW, pBlend);
999 paint.setStyle(SkPaint::Style::kFill_Style);
1001 paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, blur * 0.5));
1002 mCanvas->drawRoundRect(r, roundness, roundness, paint);
1007 #ifdef IGRAPHICS_CPU 1008 return "SKIA | CPU";
1009 #elif defined IGRAPHICS_GL2 1010 return "SKIA | GL2";
1011 #elif defined IGRAPHICS_GL3 1012 return "SKIA | GL3";
1013 #elif defined IGRAPHICS_METAL 1014 return "SKIA | Metal";
const char * GetDrawingAPIStr() override
void UpdateLayer() override
Implemented by a graphics backend to prepare for drawing to the layer at the top of the stack...
Used to manage a rectangular area, independent of draw class/platform.
virtual void DrawRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw a rectangle to the graphics context.
Used to manage composite/blend operations, independent of draw class/platform.
User-facing bitmap abstraction that you use to manage bitmap data, independant of draw class/platform...
Used to manage fill behaviour for path based drawing back ends.
bool BitmapExtSupported(const char *ext) override
Checks a file extension and reports whether this drawing API supports loading that extension...
IMatrix & Invert()
Changes the matrix to be the inverse of its original value.
virtual void BeginFrame()
Called at the beginning of drawing.
const void * LoadWinResource(const char *resID, const char *type, int &sizeInBytes, void *pHInstance)
Load a resource from the binary (windows only).
APIBitmap * CreateAPIBitmap(int width, int height, int scale, double drawScale, bool cacheable=false) override
Creates a new API bitmap, either in memory or as a GPU texture.
virtual void FillCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0)
Fill a circle with a color.
void GetLayerBitmapData(const ILayerPtr &layer, RawBitmapData &data) override
Get the contents of a layers pixels as bitmap data.
void PathArc(float cx, float cy, float r, float a1, float a2, EWinding winding) override
Add an arc to the current path.
virtual void DrawRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0, float thickness=1.f)
Draw a rounded rectangle to the graphics context.
Used to manage color data, independent of draw class/platform.
IRECT GetTranslated(float x, float y) const
Get a translated copy of this rectangle.
void DrawBitmap(const IBitmap &bitmap, const IRECT &dest, int srcX, int srcY, const IBlend *pBlend) override
Draw a bitmap (raster) image to the graphics context.
Used to manage stroke behaviour for path based drawing back ends.
void EndFrame() override
Called by some drawing API classes to finally blit the draw bitmap onto the screen or perform other c...
float R
Right side of the rectangle (X + W)
BitmapData GetBitmap() const
void DrawResize() override
An editor delegate base class for a SOMETHING that uses IGraphics for it's UI.
IText is used to manage font and text/text entry style for a piece of text on the UI...
virtual void DrawCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0, float thickness=1.f)
Draw a circle to the graphics context.
float DoMeasureText(const IText &text, const char *str, IRECT &bounds) const override
const IColorStop & GetStop(int idx) const
Get the IColorStop at a particular index (will crash if out of bounds)
virtual void FillArc(const IColor &color, float cx, float cy, float r, float a1, float a2, const IBlend *pBlend=0)
Fill an arc segment with a color.
void OnViewDestroyed() override
Called after a platform view is destroyed, so that drawing classes can e.g.
The lowest level base class of an IGraphics context.
Used to specify properties of a drop-shadow to a layer.
void ApplyShadowMask(ILayerPtr &layer, RawBitmapData &mask, const IShadow &shadow) override
Implemented by a graphics backend to apply a calculated shadow mask to a layer, according to the shad...
void OnViewInitialized(void *pContext) override
Called after platform view initialization, so that drawing classes can e.g.
virtual void FillRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0)
Fill a rounded rectangle with a color.
Used to represent a point/stop in a gradient.
virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill a rectangular region of the graphics context with a color.
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.
virtual void FillEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill an ellipse within a rectangular region of the graphics context.
virtual void DrawEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw an ellipse within a rectangular region of the graphics context.
void TransformPoint(double &x, double &y, double x0, double y0) const
Transforms the point x, y.
IColor GetPoint(int x, int y) override
Get the color at an X, Y location in the graphics context.
void DoDrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend) override
A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...
void PathStroke(const IPattern &pattern, float thickness, const IStrokeOptions &options, const IBlend *pBlend) override
Stroke the current current path.
float GetDrawScale() const
float L
Left side of the rectangle (X)
bool LoadAPIFont(const char *fontID, const PlatformFontPtr &font) override
Drawing API method to load a font from a PlatformFontPtr, called internally.
static void ToLower(char *cDest, const char *cSrc)
void BeginFrame() override
Called at the beginning of drawing.
APIBitmap * GetAPIBitmap() const
void DrawFastDropShadow(const IRECT &innerBounds, const IRECT &outerBounds, float xyDrop, float roundness, float blur, IBlend *pBlend) override
NanoVG only.
virtual void DrawArc(const IColor &color, float cx, float cy, float r, float a1, float a2, const IBlend *pBlend=0, float thickness=1.f)
Draw an arc to the graphics context.
void PathFill(const IPattern &pattern, const IFillOptions &options, const IBlend *pBlend) override
Fill the current current path.
std::unique_ptr< ILayer > ILayerPtr
ILayerPtr is a managed pointer for transferring the ownership of layers.
Used to store pattern information for gradients.
APIBitmap * LoadAPIBitmap(const char *fileNameOrResID, int scale, EResourceLocation location, const char *ext) override
Drawing API method to load a bitmap, called internally.
Used to store transformation matrices.
float T
Top of the rectangle (Y)
float B
Bottom of the rectangle (Y + H)