4#include "IGraphicsSkia.h"
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"
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 #include "include/gpu/mtl/GrMtlBackendContext.h"
29 #elif !defined IGRAPHICS_CPU
30 #error Define either IGRAPHICS_GL2, IGRAPHICS_GL3, IGRAPHICS_METAL, or IGRAPHICS_CPU for IGRAPHICS_SKIA with OS_MAC
33 #pragma comment(lib, "libpng.lib")
34 #pragma comment(lib, "zlib.lib")
35 #pragma comment(lib, "skia.lib")
36 #pragma comment(lib, "svg.lib")
37 #pragma comment(lib, "skshaper.lib")
38 #pragma comment(lib, "skunicode.lib")
39 #pragma comment(lib, "opengl32.lib")
42#if defined IGRAPHICS_GL
43 #include "gl/GrGLInterface.h"
47using namespace igraphics;
49extern std::map<std::string, MTLTexturePtr> gTextureMap;
51#pragma mark - Private Classes and Structs
56 Bitmap(sk_sp<SkSurface> surface,
int width,
int height,
float scale,
float drawScale);
57 Bitmap(
const char* path,
double sourceScale);
58 Bitmap(
const void* pData,
int size,
double sourceScale);
59 Bitmap(sk_sp<SkImage>,
double sourceScale);
62 SkiaDrawable mDrawable;
65IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkSurface> surface,
int width,
int height,
float scale,
float drawScale)
67 mDrawable.mSurface = surface;
68 mDrawable.mIsSurface =
true;
70 SetBitmap(&mDrawable, width, height, scale, drawScale);
73IGraphicsSkia::Bitmap::Bitmap(
const char* path,
double sourceScale)
75 sk_sp<SkData> data = SkData::MakeFromFileName(path);
77 assert(data &&
"Unable to load file at path");
79 auto image = SkImage::MakeFromEncoded(data);
82 image = image->makeRasterImage();
85 mDrawable.mImage = image;
87 mDrawable.mIsSurface =
false;
88 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
91IGraphicsSkia::Bitmap::Bitmap(
const void* pData,
int size,
double sourceScale)
93 auto data = SkData::MakeWithoutCopy(pData, size);
94 auto image = SkImage::MakeFromEncoded(data);
97 image = image->makeRasterImage();
100 mDrawable.mImage = image;
102 mDrawable.mIsSurface =
false;
103 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
106IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkImage> image,
double sourceScale)
109 mDrawable.mImage = image->makeRasterImage();
111 mDrawable.mImage = image;
114 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
117struct IGraphicsSkia::Font
119 Font(IFontDataPtr&& data, sk_sp<SkTypeface> typeFace)
120 : mData(std::move(data)), mTypeface(typeFace) {}
123 sk_sp<SkTypeface> mTypeface;
127StaticStorage<IGraphicsSkia::Font> IGraphicsSkia::sFontCache;
129#pragma mark - Utility conversions
132BEGIN_IGRAPHICS_NAMESPACE
134SkColor SkiaColor(
const IColor& color,
const IBlend* pBlend)
137 return SkColorSetARGB(
Clip(
static_cast<int>(pBlend->mWeight * color.A), 0, 255), color.R, color.G, color.B);
139 return SkColorSetARGB(color.A, color.R, color.G, color.B);
142SkRect SkiaRect(
const IRECT& r)
144 return SkRect::MakeLTRB(r.L, r.T, r.R, r.B);
147SkBlendMode SkiaBlendMode(
const IBlend* pBlend)
150 return SkBlendMode::kSrcOver;
152 switch (pBlend->mMethod)
154 case EBlend::SrcOver:
return SkBlendMode::kSrcOver;
155 case EBlend::SrcIn:
return SkBlendMode::kSrcIn;
156 case EBlend::SrcOut:
return SkBlendMode::kSrcOut;
157 case EBlend::SrcAtop:
return SkBlendMode::kSrcATop;
158 case EBlend::DstOver:
return SkBlendMode::kDstOver;
159 case EBlend::DstIn:
return SkBlendMode::kDstIn;
160 case EBlend::DstOut:
return SkBlendMode::kDstOut;
161 case EBlend::DstAtop:
return SkBlendMode::kDstATop;
162 case EBlend::Add:
return SkBlendMode::kPlus;
163 case EBlend::XOR:
return SkBlendMode::kXor;
166 return SkBlendMode::kClear;
169SkTileMode SkiaTileMode(
const IPattern& pattern)
171 switch (pattern.mExtend)
173 case EPatternExtend::None:
return SkTileMode::kDecal;
174 case EPatternExtend::Reflect:
return SkTileMode::kMirror;
175 case EPatternExtend::Repeat:
return SkTileMode::kRepeat;
176 case EPatternExtend::Pad:
return SkTileMode::kClamp;
179 return SkTileMode::kClamp;
185 paint.setAntiAlias(
true);
186 paint.setBlendMode(SkiaBlendMode(pBlend));
187 int numStops = pattern.
NStops();
189 if (pattern.mType == EPatternType::Solid || numStops < 2)
191 paint.setColor(SkiaColor(pattern.
GetStop(0).mColor, pBlend));
200 IMatrix m = pattern.mTransform;
207 SkPoint::Make(x1, y1),
208 SkPoint::Make(x2, y2)
212 SkScalar positions[8];
214 assert(numStops <= 8);
216 for(
int i = 0; i < numStops; i++)
219 colors[i] = SkiaColor(stop.mColor, pBlend);
220 positions[i] = stop.mOffset;
223 switch (pattern.mType)
225 case EPatternType::Linear:
226 paint.setShader(SkGradientShader::MakeLinear(points, colors, positions, numStops, SkiaTileMode(pattern), 0,
nullptr));
229 case EPatternType::Radial:
231 float xd = points[0].x() - points[1].x();
232 float yd = points[0].y() - points[1].y();
233 float radius = std::sqrt(xd * xd + yd * yd);
234 paint.setShader(SkGradientShader::MakeRadial(points[0], radius, colors, positions, numStops, SkiaTileMode(pattern), 0,
nullptr));
238 case EPatternType::Sweep:
240 SkMatrix matrix = SkMatrix::MakeAll(m.mXX, m.mYX, 0, m.mXY, m.mYY, 0, 0, 0, 1);
242 paint.setShader(SkGradientShader::MakeSweep(x1, y1, colors,
nullptr, numStops, SkTileMode::kDecal,
243 0, 360 * positions[numStops - 1], 0, &matrix));
256END_IGRAPHICS_NAMESPACE
261IGraphicsSkia::IGraphicsSkia(
IGEditorDelegate& dlg,
int w,
int h,
int fps,
float scale)
264 mMainPath.setIsVolatile(
true);
266#if defined IGRAPHICS_CPU
267 DBGMSG(
"IGraphics Skia CPU @ %i FPS\n", fps);
268#elif defined IGRAPHICS_METAL
269 DBGMSG(
"IGraphics Skia METAL @ %i FPS\n", fps);
270#elif defined IGRAPHICS_GL
271 DBGMSG(
"IGraphics Skia GL @ %i FPS\n", fps);
273 StaticStorage<Font>::Accessor storage(sFontCache);
277IGraphicsSkia::~IGraphicsSkia()
279 StaticStorage<Font>::Accessor storage(sFontCache);
287 return (strstr(extLower,
"png") !=
nullptr) || (strstr(extLower,
"jpg") !=
nullptr) || (strstr(extLower,
"jpeg") !=
nullptr);
310 if (location == EResourceLocation::kWinBinary)
314 return new Bitmap(pData, size, scale);
318 return new Bitmap(fileNameOrResID, scale);
323 return new Bitmap(pData, dataSize, scale);
328#if defined IGRAPHICS_GL
329 auto glInterface = GrGLMakeNativeInterface();
330 mGrContext = GrDirectContext::MakeGL(glInterface);
331#elif defined IGRAPHICS_METAL
332 CAMetalLayer* pMTLLayer = (CAMetalLayer*) pContext;
333 id<MTLDevice> device = pMTLLayer.device;
334 id<MTLCommandQueue> commandQueue = [device newCommandQueue];
335 GrMtlBackendContext backendContext = {};
336 backendContext.fDevice.retain((__bridge GrMTLHandle) device);
337 backendContext.fQueue.retain((__bridge GrMTLHandle) commandQueue);
338 mGrContext = GrDirectContext::MakeMetal(backendContext);
339 mMTLDevice = (
void*) device;
340 mMTLCommandQueue = (
void*) commandQueue;
341 mMTLLayer = pContext;
351#if defined IGRAPHICS_GL
353 mScreenSurface =
nullptr;
354 mGrContext =
nullptr;
355#elif defined IGRAPHICS_METAL
356 [(id<MTLCommandQueue>) mMTLCommandQueue release];
357 mMTLCommandQueue =
nullptr;
359 mMTLDevice =
nullptr;
368#if defined IGRAPHICS_GL || defined IGRAPHICS_METAL
369 if (mGrContext.get())
371 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
372 mSurface = SkSurface::MakeRenderTarget(mGrContext.get(), SkBudgeted::kYes, info);
378 const size_t bmpSize =
sizeof(BITMAPINFOHEADER) + (w * h *
sizeof(uint32_t));
379 mSurfaceMemory.Resize(bmpSize);
380 BITMAPINFO* bmpInfo =
reinterpret_cast<BITMAPINFO*
>(mSurfaceMemory.Get());
381 ZeroMemory(bmpInfo,
sizeof(BITMAPINFO));
382 bmpInfo->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
383 bmpInfo->bmiHeader.biWidth = w;
384 bmpInfo->bmiHeader.biHeight = -h;
385 bmpInfo->bmiHeader.biPlanes = 1;
386 bmpInfo->bmiHeader.biBitCount = 32;
387 bmpInfo->bmiHeader.biCompression = BI_RGB;
388 void* pixels = bmpInfo->bmiColors;
390 SkImageInfo info = SkImageInfo::Make(w, h, kN32_SkColorType, kPremul_SkAlphaType,
nullptr);
391 mSurface = SkSurface::MakeRasterDirect(info, pixels,
sizeof(uint32_t) * w);
393 mSurface = SkSurface::MakeRasterN32Premul(w, h);
398 mCanvas = mSurface->getCanvas();
405#if defined IGRAPHICS_GL
406 if (mGrContext.get())
412 int fbo = 0, samples = 0, stencilBits = 0;
413 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
414 glGetIntegerv(GL_SAMPLES, &samples);
416 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencilBits);
418 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
421 GrGLFramebufferInfo fbinfo;
423 fbinfo.fFormat = 0x8058;
425 GrBackendRenderTarget backendRT(width, height, samples, stencilBits, fbinfo);
427 mScreenSurface = SkSurface::MakeFromBackendRenderTarget(mGrContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
nullptr,
nullptr);
428 assert(mScreenSurface);
430#elif defined IGRAPHICS_METAL
431 if (mGrContext.get())
436 id<CAMetalDrawable> drawable = [(CAMetalLayer*) mMTLLayer nextDrawable];
438 GrMtlTextureInfo fbInfo;
439 fbInfo.fTexture.retain((
const void*)(drawable.texture));
440 GrBackendRenderTarget backendRT(width, height, 1 , fbInfo);
442 mScreenSurface = SkSurface::MakeFromBackendRenderTarget(mGrContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType,
nullptr,
nullptr);
444 mMTLDrawable = (
void*) drawable;
445 assert(mScreenSurface);
455 #if defined OS_MAC || defined OS_IOS
457 mSurface->peekPixels(&pixmap);
459 bmp.installPixels(pixmap);
461 CGContextSaveGState(pCGContext);
463 SkCGDrawBitmap(pCGContext, bmp, 0, 0);
464 CGContextRestoreGState(pCGContext);
468 BITMAPINFO* bmpInfo =
reinterpret_cast<BITMAPINFO*
>(mSurfaceMemory.Get());
471 HDC hdc = BeginPaint(hWnd, &ps);
472 StretchDIBits(hdc, 0, 0, w, h, 0, 0, w, h, bmpInfo->bmiColors, bmpInfo, DIB_RGB_COLORS, SRCCOPY);
473 ReleaseDC(hWnd, hdc);
476 #error NOT IMPLEMENTED
479 mSurface->draw(mScreenSurface->getCanvas(), 0.0, 0.0,
nullptr);
481 mScreenSurface->getCanvas()->flush();
483 #ifdef IGRAPHICS_METAL
484 id<MTLCommandBuffer> commandBuffer = [(id<MTLCommandQueue>) mMTLCommandQueue commandBuffer];
485 commandBuffer.label =
@"Present";
487 [commandBuffer presentDrawable:(id<CAMetalDrawable>) mMTLDrawable];
488 [commandBuffer commit];
497 p.setAntiAlias(
true);
498 p.setBlendMode(SkiaBlendMode(pBlend));
500 p.setAlpha(
Clip(
static_cast<int>(pBlend->mWeight * 255), 0, 255));
508 mCanvas->clipRect(SkiaRect(dest));
509 mCanvas->translate(dest.L, dest.T);
510 mCanvas->scale(scale1, scale1);
511 mCanvas->translate(-srcX * scale2, -srcY * scale2);
514 auto samplingOptions = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
516 auto samplingOptions = SkSamplingOptions(SkCubicResampler::Mitchell());
519 if (image->mIsSurface)
520 image->mSurface->draw(mCanvas, 0.0, 0.0, samplingOptions, &p);
522 mCanvas->drawImage(image->mImage, 0.0, 0.0, samplingOptions, &p);
530 arc.setIsVolatile(
true);
532 float sweep = (a2 - a1);
534 if (sweep >= 360.f || sweep <= -360.f)
536 arc.addCircle(cx, cy, r);
537 mMainPath.addPath(arc, mMatrix, SkPath::kAppend_AddPathMode);
541 if (winding == EWinding::CW)
552 arc.arcTo(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, sweep,
false);
553 mMainPath.addPath(arc, mMatrix, SkPath::kExtend_AddPathMode);
560 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
561 mCanvas->readPixels(bitmap, x, y);
562 auto color = bitmap.getColor(0,0);
563 return IColor(SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
568 StaticStorage<Font>::Accessor storage(sFontCache);
569 Font* cached = storage.Find(fontID);
574 IFontDataPtr data = font->GetFontData();
578 auto wrappedData = SkData::MakeWithoutCopy(data->Get(), data->GetSize());
579 int index = data->GetFaceIdx();
580 auto typeface = SkTypeface::MakeFromData(wrappedData, index);
584 storage.Add(
new Font(std::move(data), typeface), fontID);
592void IGraphicsSkia::PrepareAndMeasureText(
const IText& text,
const char* str,
IRECT& r,
double& x,
double & y, SkFont& font)
const
594 SkFontMetrics metrics;
598 StaticStorage<Font>::Accessor storage(sFontCache);
599 Font* pFont = storage.Find(text.mFont);
601 assert(pFont &&
"No font found - did you forget to load it?");
603 font.setTypeface(pFont->mTypeface);
604 font.setHinting(SkFontHinting::kSlight);
605 font.setForceAutoHinting(
false);
606 font.setSubpixel(
true);
607 font.setSize(text.mSize * pFont->mData->GetHeightEMRatio());
610 const double textWidth = font.measureText(str, strlen(str), SkTextEncoding::kUTF8,
nullptr);
611 font.getMetrics(&metrics);
613 const double textHeight = text.mSize;
614 const double ascender = metrics.fAscent;
615 const double descender = metrics.fDescent;
619 case EAlign::Near: x = r.L;
break;
620 case EAlign::Center: x = r.
MW() - (textWidth / 2.0);
break;
621 case EAlign::Far: x = r.R - textWidth;
break;
624 switch (text.mVAlign)
626 case EVAlign::Top: y = r.T - ascender;
break;
627 case EVAlign::Middle: y = r.
MH() - descender + (textHeight / 2.0);
break;
628 case EVAlign::Bottom: y = r.B - descender;
break;
631 r =
IRECT((
float) x, (
float) y + ascender, (
float) (x + textWidth), (
float) (y + ascender + textHeight));
637 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
641 PrepareAndMeasureText(text, str, bounds, x, y, font);
648 IRECT measured = bounds;
651 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
655 PrepareAndMeasureText(text, str, measured, x, y, font);
657 DoTextRotation(text, bounds, measured);
659 paint.setColor(SkiaColor(text.mFGColor, pBlend));
660 mCanvas->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint);
666 SkPaint paint = SkiaPaint(pattern, pBlend);
667 paint.setStyle(SkPaint::kStroke_Style);
669 switch (options.mCapOption)
671 case ELineCap::Butt: paint.setStrokeCap(SkPaint::kButt_Cap);
break;
672 case ELineCap::Round: paint.setStrokeCap(SkPaint::kRound_Cap);
break;
673 case ELineCap::Square: paint.setStrokeCap(SkPaint::kSquare_Cap);
break;
676 switch (options.mJoinOption)
678 case ELineJoin::Miter: paint.setStrokeJoin(SkPaint::kMiter_Join);
break;
679 case ELineJoin::Round: paint.setStrokeJoin(SkPaint::kRound_Join);
break;
680 case ELineJoin::Bevel: paint.setStrokeJoin(SkPaint::kBevel_Join);
break;
683 if (options.mDash.GetCount())
686 int dashCount = options.mDash.GetCount();
687 int dashMax = dashCount & 1 ? dashCount * 2 : dashCount;
690 for (
int i = 0; i < dashMax; i += 2)
692 dashArray[i + 0] = options.mDash.GetArray()[i % dashCount];
693 dashArray[i + 1] = options.mDash.GetArray()[(i + 1) % dashCount];
696 paint.setPathEffect(SkDashPathEffect::Make(dashArray, dashMax, options.mDash.GetOffset()));
699 paint.setStrokeWidth(thickness);
700 paint.setStrokeMiter(options.mMiterLimit);
704 if (!options.mPreserve)
710 SkPaint paint = SkiaPaint(pattern, pBlend);
711 paint.setStyle(SkPaint::kFill_Style);
713 if (options.mFillRule == EFillRule::Winding)
714 mMainPath.setFillType(SkPathFillType::kWinding);
716 mMainPath.setFillType(SkPathFillType::kEvenOdd);
720 if (!options.mPreserve)
724#ifdef IGRAPHICS_DRAWFILL_DIRECT
727 auto paint = SkiaPaint(color, pBlend);
728 paint.setStyle(SkPaint::Style::kStroke_Style);
729 paint.setStrokeWidth(thickness);
730 mCanvas->drawRect(SkiaRect(bounds), paint);
735 auto paint = SkiaPaint(color, pBlend);
736 paint.setStyle(SkPaint::Style::kStroke_Style);
737 paint.setStrokeWidth(thickness);
738 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
743 auto paint = SkiaPaint(color, pBlend);
744 paint.setStyle(SkPaint::Style::kStroke_Style);
745 paint.setStrokeWidth(thickness);
746 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1),
false, paint);
751 auto paint = SkiaPaint(color, pBlend);
752 paint.setStyle(SkPaint::Style::kStroke_Style);
753 paint.setStrokeWidth(thickness);
754 mCanvas->drawCircle(cx, cy, r, paint);
759 auto paint = SkiaPaint(color, pBlend);
760 paint.setStyle(SkPaint::Style::kStroke_Style);
761 paint.setStrokeWidth(thickness);
762 mCanvas->drawOval(SkiaRect(bounds), paint);
767 auto paint = SkiaPaint(color, pBlend);
768 paint.setStyle(SkPaint::Style::kFill_Style);
769 mCanvas->drawRect(SkiaRect(bounds), paint);
774 auto paint = SkiaPaint(color, pBlend);
775 paint.setStyle(SkPaint::Style::kFill_Style);
776 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
781 auto paint = SkiaPaint(color, pBlend);
782 paint.setStyle(SkPaint::Style::kFill_Style);
783 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1),
true, paint);
788 auto paint = SkiaPaint(color, pBlend);
789 paint.setStyle(SkPaint::Style::kFill_Style);
790 mCanvas->drawCircle(cx, cy, r, paint);
795 auto paint = SkiaPaint(color, pBlend);
796 paint.setStyle(SkPaint::Style::kFill_Style);
797 mCanvas->drawOval(SkiaRect(bounds), paint);
801void IGraphicsSkia::RenderPath(SkPaint& paint)
805 if (!mMatrix.isIdentity() && mMatrix.invert(&invMatrix))
808 path.setIsVolatile(
true);
809 mMainPath.transform(invMatrix, &path);
810 mCanvas->drawPath(path, paint);
814 mCanvas->drawPath(mMainPath, paint);
818void IGraphicsSkia::PathTransformSetMatrix(
const IMatrix& m)
820 double xTranslate = 0.0;
821 double yTranslate = 0.0;
826 if (!mLayers.empty())
828 IRECT bounds = mLayers.top()->Bounds();
830 xTranslate = -bounds.L;
831 yTranslate = -bounds.T;
834 mMatrix = SkMatrix::MakeAll(m.mXX, m.mXY, m.mTX, m.mYX, m.mYY, m.mTY, 0, 0, 1);
836 SkMatrix globalMatrix = SkMatrix::Scale(scale, scale);
837 mClipMatrix = SkMatrix();
838 mFinalMatrix = mMatrix;
839 globalMatrix.preTranslate(xTranslate, yTranslate);
840 mClipMatrix.postConcat(globalMatrix);
841 mFinalMatrix.postConcat(globalMatrix);
842 mCanvas->setMatrix(mFinalMatrix);
845void IGraphicsSkia::SetClipRegion(
const IRECT& r)
847 mCanvas->restoreToCount(0);
849 mCanvas->setMatrix(mClipMatrix);
850 mCanvas->clipRect(SkiaRect(r));
851 mCanvas->setMatrix(mFinalMatrix);
856 sk_sp<SkSurface> surface;
858 #ifndef IGRAPHICS_CPU
859 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
862 surface = SkSurface::MakeRasterN32Premul(width, height);
866 surface = SkSurface::MakeRenderTarget(mGrContext.get(), SkBudgeted::kYes, info);
869 surface = SkSurface::MakeRasterN32Premul(width, height);
872 surface->getCanvas()->save();
874 return new Bitmap(std::move(surface), width, height, scale, drawScale);
879 mCanvas = mLayers.empty() ? mSurface->getCanvas() : mLayers.top()->GetAPIBitmap()->GetBitmap()->mSurface->getCanvas();
882static size_t CalcRowBytes(
int width)
884 width = ((width + 7) & (-8));
885 return width *
sizeof(uint32_t);
890 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
891 size_t rowBytes = CalcRowBytes(pDrawable->mSurface->width());
892 int size = pDrawable->mSurface->height() *
static_cast<int>(rowBytes);
896 if (data.GetSize() >= size)
898 SkImageInfo info = SkImageInfo::MakeN32Premul(pDrawable->mSurface->width(), pDrawable->mSurface->height());
899 pDrawable->mSurface->readPixels(info, data.Get(), rowBytes, 0, 0);
905 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
906 int width = pDrawable->mSurface->width();
907 int height = pDrawable->mSurface->height();
908 size_t rowBytes = CalcRowBytes(width);
909 double scale = layer->GetAPIBitmap()->GetDrawScale() * layer->GetAPIBitmap()->GetScale();
911 SkCanvas* pCanvas = pDrawable->mSurface->getCanvas();
916 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
917 SkPixmap pixMap(info, mask.Get(), rowBytes);
918 sk_sp<SkImage> image = SkImage::MakeFromRaster(pixMap,
nullptr,
nullptr);
919 sk_sp<SkImage> foreground;
923 if (shadow.mDrawForeground)
924 foreground = pDrawable->mSurface->makeImageSnapshot();
926 pCanvas->clear(SK_ColorTRANSPARENT);
928 IBlend blend(EBlend::Default, shadow.mOpacity);
929 pCanvas->setMatrix(m);
930 pCanvas->drawImage(image.get(), shadow.mXOffset * scale, shadow.mYOffset * scale);
931 m = SkMatrix::Scale(scale, scale);
932 pCanvas->setMatrix(m);
933 pCanvas->translate(-layer->Bounds().L, -layer->Bounds().T);
934 SkPaint p = SkiaPaint(shadow.mPattern, &blend);
935 p.setBlendMode(SkBlendMode::kSrcIn);
936 pCanvas->drawPaint(p);
938 if (shadow.mDrawForeground)
941 pCanvas->setMatrix(m);
942 pCanvas->drawImage(foreground.get(), 0.0, 0.0);
948 SkRect r = SkiaRect(innerBounds.
GetTranslated(xyDrop, xyDrop));
950 SkPaint paint = SkiaPaint(COLOR_BLACK_DROP_SHADOW, pBlend);
951 paint.setStyle(SkPaint::Style::kFill_Style);
953 paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, blur * 0.5));
954 mCanvas->drawRoundRect(r, roundness, roundness, paint);
961#elif defined IGRAPHICS_GL2
963#elif defined IGRAPHICS_GL3
965#elif defined IGRAPHICS_METAL
966 return "SKIA | Metal";
const void * LoadWinResource(const char *resID, const char *type, int &sizeInBytes, void *pHInstance)
Load a resource from the binary (windows only).
A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...
BitmapData GetBitmap() const
void SetBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
Used to initialise the members after construction.
User-facing bitmap abstraction that you use to manage bitmap data, independant of draw class/platform...
float GetDrawScale() const
APIBitmap * GetAPIBitmap() const
An editor delegate base class for a SOMETHING that uses IGraphics for it's UI.
The lowest level base class of an IGraphics context.
virtual void DrawRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw a rectangle to the graphics context.
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.
float GetTotalScale() const
Gets the combined draw and screen/display scaling factor.
virtual void * GetWindow()=0
Get a pointer to the platform view e.g.
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.
void DoMeasureTextRotation(const IText &text, const IRECT &bounds, IRECT &rect) const
int WindowWidth() const
Gets the width of the graphics context including draw scaling.
void PathTransformRestore()
Restore the affine transform of the current path, to the previously saved state.
virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill a rectangular region of the graphics context with a color.
void * GetPlatformContext()
Get the platform level draw context - an HDC or CGContextRef.
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 RemoveAllControls()
Removes all regular IControls from the control list, as well as special controls (frees memory).
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.
virtual void FillRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0)
Fill a rounded rectangle with a color.
virtual void * GetWinModuleHandle()
float GetScreenScale() const
Gets the screen/display scaling factor, e.g.
void PathTransformSave()
Save the current affine transform of the current path.
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.
int WindowHeight() const
Gets the height of the graphics context including draw scaling.
virtual void BeginFrame()
Called at the beginning of drawing.
virtual void FillCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0)
Fill a circle with a color.
APIBitmap * LoadAPIBitmap(const char *fileNameOrResID, int scale, EResourceLocation location, const char *ext) override
Drawing API method to load a bitmap, called internally.
void BeginFrame() override
Called at the beginning of drawing.
void GetLayerBitmapData(const ILayerPtr &layer, RawBitmapData &data) override
Get the contents of a layer as Raw RGBA bitmap data NOTE: you should only call this within IControl::...
void DrawResize() override
void DoDrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend) override
void PathStroke(const IPattern &pattern, float thickness, const IStrokeOptions &options, const IBlend *pBlend) override
Stroke the current current path.
void EndFrame() override
Called by some drawing API classes to finally blit the draw bitmap onto the screen or perform other c...
float DoMeasureText(const IText &text, const char *str, IRECT &bounds) const override
void PathArc(float cx, float cy, float r, float a1, float a2, EWinding winding) override
Add an arc to the current path.
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...
const char * GetDrawingAPIStr() override
APIBitmap * CreateAPIBitmap(int width, int height, float scale, double drawScale, bool cacheable=false) override
Creates a new API bitmap, either in memory or as a GPU texture.
bool LoadAPIFont(const char *fontID, const PlatformFontPtr &font) override
Drawing API method to load a font from a PlatformFontPtr, called internally.
void OnViewInitialized(void *pContext) override
Called after platform view initialization, so that drawing classes can e.g.
void UpdateLayer() override
Implemented by a graphics backend to prepare for drawing to the layer at the top of the stack.
void PathFill(const IPattern &pattern, const IFillOptions &options, const IBlend *pBlend) override
Fill the current current path.
bool BitmapExtSupported(const char *ext) override
Checks a file extension and reports whether this drawing API supports loading that extension.
IColor GetPoint(int x, int y) override
Get the color at an X, Y location in the graphics context.
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.
void DrawFastDropShadow(const IRECT &innerBounds, const IRECT &outerBounds, float xyDrop, float roundness, float blur, IBlend *pBlend) override
NanoVG only.
void OnViewDestroyed() override
Called after a platform view is destroyed, so that drawing classes can e.g.
std::unique_ptr< ILayer > ILayerPtr
ILayerPtr is a managed pointer for transferring the ownership of layers.
Used to manage stroke behaviour for path based drawing back ends.
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.
static void ToLower(char *cDest, const char *cSrc)
Used to manage composite/blend operations, independent of draw class/platform.
Used to manage color data, independent of draw class/platform.
Used to represent a point/stop in a gradient.
Used to manage fill behaviour.
Used to store transformation matrices.
IMatrix & Invert()
Changes the matrix to be the inverse of its original value.
void TransformPoint(double &x, double &y, double x0, double y0) const
Transforms the point x, y.
Used to store pattern information for gradients.
const IColorStop & GetStop(int idx) const
Get the IColorStop at a particular index (will crash if out of bounds)
Used to manage a rectangular area, independent of draw class/platform.
IRECT GetTranslated(float x, float y) const
Get a translated copy of this rectangle.
Used to specify properties of a drop-shadow to a layer.
IText is used to manage font and text/text entry style for a piece of text on the UI,...