iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsSkia.cpp
1#include <cmath>
2#include <map>
3
4#include "IGraphicsSkia.h"
5
6#pragma warning( push )
7#pragma warning( disable : 4244 )
8#include "include/core/SkMaskFilter.h"
9#include "include/core/SkBlurTypes.h"
10#include "include/core/SkFont.h"
11#include "include/core/SkFontMetrics.h"
12#include "include/core/SkTypeface.h"
13#include "include/core/SkVertices.h"
14#include "include/core/SkSwizzle.h"
15#include "include/core/SkBitmap.h"
16#include "include/core/SkFontMgr.h"
17#include "include/core/SkPathEffect.h"
18#include "include/effects/SkDashPathEffect.h"
19#include "include/effects/SkGradientShader.h"
20
21#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
22#include "modules/skparagraph/include/FontCollection.h"
23#include "modules/skparagraph/include/Paragraph.h"
24#include "modules/skparagraph/include/ParagraphBuilder.h"
25#include "modules/skparagraph/include/ParagraphStyle.h"
26#include "modules/skparagraph/include/TextStyle.h"
27#include "modules/skshaper/include/SkShaper.h"
28#include "modules/skunicode/include/SkUnicode_icu.h"
29#endif
30#pragma warning( pop )
31#include "include/gpu/ganesh/SkSurfaceGanesh.h"
32#include "include/gpu/GrBackendSurface.h"
33
34#if defined OS_MAC || defined OS_IOS
35 #include "include/utils/mac/SkCGUtils.h"
36 #if defined IGRAPHICS_GL2
37 #error SKIA doesn't work correctly with IGRAPHICS_GL2
38 #elif defined IGRAPHICS_GL3
39 #include <OpenGL/gl3.h>
40 #elif defined IGRAPHICS_METAL
41 // even though this is a .cpp we are in an objc(pp) compilation unit
42 #import <Metal/Metal.h>
43 #import <QuartzCore/CAMetalLayer.h>
44 #include "include/gpu/ganesh/mtl/GrMtlBackendContext.h"
45 #include "include/gpu/ganesh/mtl/GrMtlDirectContext.h"
46 #include "include/gpu/ganesh/mtl/GrMtlBackendSurface.h"
47 #elif !defined IGRAPHICS_CPU
48 #error Define either IGRAPHICS_GL2, IGRAPHICS_GL3, IGRAPHICS_METAL, or IGRAPHICS_CPU for IGRAPHICS_SKIA with OS_MAC
49 #endif
50
51 #include "include/ports/SkFontMgr_mac_ct.h"
52
53#elif defined OS_WIN
54 #include "include/ports/SkTypeface_win.h"
55
56 #pragma comment(lib, "skia.lib")
57
58 #ifndef IGRAPHICS_NO_SKIA_SKPARAGRAPH
59 #pragma comment(lib, "skparagraph.lib")
60 #pragma comment(lib, "skshaper.lib")
61 #pragma comment(lib, "skunicode_core.lib")
62 #pragma comment(lib, "skunicode_icu.lib")
63 #endif
64
65
66#endif
67
68#if defined IGRAPHICS_GL
69 #include "include/gpu/gl/GrGLInterface.h"
70 #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
71 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
72
73 #if defined OS_MAC
74 #include "include/gpu/ganesh/gl/mac/GrGLMakeMacInterface.h"
75 #elif defined OS_WIN
76 #include "include/gpu/ganesh/gl/win/GrGLMakeWinInterface.h"
77 #pragma comment(lib, "opengl32.lib")
78 #endif
79
80#endif
81
82using namespace iplug;
83using namespace igraphics;
84
85extern std::map<std::string, MTLTexturePtr> gTextureMap;
86
87#pragma mark - Private Classes and Structs
88
90{
91public:
92 Bitmap(sk_sp<SkSurface> surface, int width, int height, float scale, float drawScale);
93 Bitmap(const char* path, double sourceScale);
94 Bitmap(const void* pData, int size, double sourceScale);
95 Bitmap(sk_sp<SkImage>, double sourceScale);
96
97private:
98 SkiaDrawable mDrawable;
99};
100
101IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkSurface> surface, int width, int height, float scale, float drawScale)
102{
103 mDrawable.mSurface = surface;
104 mDrawable.mIsSurface = true;
105
106 SetBitmap(&mDrawable, width, height, scale, drawScale);
107}
108
109IGraphicsSkia::Bitmap::Bitmap(const char* path, double sourceScale)
110{
111 sk_sp<SkData> data = SkData::MakeFromFileName(path);
112
113 assert(data && "Unable to load file at path");
114
115 auto image = SkImages::DeferredFromEncodedData(data);
116
117#ifdef IGRAPHICS_CPU
118 image = image->makeRasterImage();
119#endif
120
121 mDrawable.mImage = image;
122
123 mDrawable.mIsSurface = false;
124 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
125}
126
127IGraphicsSkia::Bitmap::Bitmap(const void* pData, int size, double sourceScale)
128{
129 auto data = SkData::MakeWithoutCopy(pData, size);
130 auto image = SkImages::DeferredFromEncodedData(data);
131
132#ifdef IGRAPHICS_CPU
133 image = image->makeRasterImage();
134#endif
135
136 mDrawable.mImage = image;
137
138 mDrawable.mIsSurface = false;
139 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
140}
141
142IGraphicsSkia::Bitmap::Bitmap(sk_sp<SkImage> image, double sourceScale)
143{
144#ifdef IGRAPHICS_CPU
145 mDrawable.mImage = image->makeRasterImage();
146#else
147 mDrawable.mImage = image;
148#endif
149
150 SetBitmap(&mDrawable, mDrawable.mImage->width(), mDrawable.mImage->height(), sourceScale, 1.f);
151}
152
153struct IGraphicsSkia::Font
154{
155 Font(IFontDataPtr&& data, sk_sp<SkTypeface> typeFace)
156 : mData(std::move(data)), mTypeface(typeFace) {}
157
158 IFontDataPtr mData;
159 sk_sp<SkTypeface> mTypeface;
160};
161
162// Fonts
163StaticStorage<IGraphicsSkia::Font> IGraphicsSkia::sFontCache;
164
165#pragma mark - Utility conversions
166
167BEGIN_IPLUG_NAMESPACE
168BEGIN_IGRAPHICS_NAMESPACE
169
170SkColor SkiaColor(const IColor& color, const IBlend* pBlend)
171{
172 if (pBlend)
173 return SkColorSetARGB(Clip(static_cast<int>(pBlend->mWeight * color.A), 0, 255), color.R, color.G, color.B);
174 else
175 return SkColorSetARGB(color.A, color.R, color.G, color.B);
176}
177
178SkRect SkiaRect(const IRECT& r)
179{
180 return SkRect::MakeLTRB(r.L, r.T, r.R, r.B);
181}
182
183SkBlendMode SkiaBlendMode(const IBlend* pBlend)
184{
185 if (!pBlend)
186 return SkBlendMode::kSrcOver;
187
188 switch (pBlend->mMethod)
189 {
190 case EBlend::SrcOver: return SkBlendMode::kSrcOver;
191 case EBlend::SrcIn: return SkBlendMode::kSrcIn;
192 case EBlend::SrcOut: return SkBlendMode::kSrcOut;
193 case EBlend::SrcAtop: return SkBlendMode::kSrcATop;
194 case EBlend::DstOver: return SkBlendMode::kDstOver;
195 case EBlend::DstIn: return SkBlendMode::kDstIn;
196 case EBlend::DstOut: return SkBlendMode::kDstOut;
197 case EBlend::DstAtop: return SkBlendMode::kDstATop;
198 case EBlend::Add: return SkBlendMode::kPlus;
199 case EBlend::XOR: return SkBlendMode::kXor;
200 }
201
202 return SkBlendMode::kClear;
203}
204
205SkTileMode SkiaTileMode(const IPattern& pattern)
206{
207 switch (pattern.mExtend)
208 {
209 case EPatternExtend::None: return SkTileMode::kDecal;
210 case EPatternExtend::Reflect: return SkTileMode::kMirror;
211 case EPatternExtend::Repeat: return SkTileMode::kRepeat;
212 case EPatternExtend::Pad: return SkTileMode::kClamp;
213 }
214
215 return SkTileMode::kClamp;
216}
217
218SkPaint SkiaPaint(const IPattern& pattern, const IBlend* pBlend)
219{
220 SkPaint paint;
221 paint.setAntiAlias(true);
222 paint.setBlendMode(SkiaBlendMode(pBlend));
223 int numStops = pattern.NStops();
224
225 if (pattern.mType == EPatternType::Solid || numStops < 2)
226 {
227 paint.setColor(SkiaColor(pattern.GetStop(0).mColor, pBlend));
228 }
229 else
230 {
231 double x1 = 0.0;
232 double y1 = 0.0;
233 double x2 = 0.0;
234 double y2 = 1.0;
235
236 IMatrix m = pattern.mTransform;
237 m.Invert();
238 m.TransformPoint(x1, y1);
239 m.TransformPoint(x2, y2);
240
241 SkPoint points[2] =
242 {
243 SkPoint::Make(x1, y1),
244 SkPoint::Make(x2, y2)
245 };
246
247 SkColor colors[8];
248 SkScalar positions[8];
249
250 assert(numStops <= 8);
251
252 for(int i = 0; i < numStops; i++)
253 {
254 const IColorStop& stop = pattern.GetStop(i);
255 colors[i] = SkiaColor(stop.mColor, pBlend);
256 positions[i] = stop.mOffset;
257 }
258
259 switch (pattern.mType)
260 {
261 case EPatternType::Linear:
262 paint.setShader(SkGradientShader::MakeLinear(points, colors, positions, numStops, SkiaTileMode(pattern), 0, nullptr));
263 break;
264
265 case EPatternType::Radial:
266 {
267 float xd = points[0].x() - points[1].x();
268 float yd = points[0].y() - points[1].y();
269 float radius = std::sqrt(xd * xd + yd * yd);
270 paint.setShader(SkGradientShader::MakeRadial(points[0], radius, colors, positions, numStops, SkiaTileMode(pattern), 0, nullptr));
271 break;
272 }
273
274 case EPatternType::Sweep:
275 {
276 SkMatrix matrix = SkMatrix::MakeAll(m.mXX, m.mYX, 0, m.mXY, m.mYY, 0, 0, 0, 1);
277
278 paint.setShader(SkGradientShader::MakeSweep(x1, y1, colors, nullptr, numStops, SkTileMode::kDecal,
279 0, 360 * positions[numStops - 1], 0, &matrix));
280
281 break;
282 }
283
284 default:
285 break;
286 }
287 }
288
289 return paint;
290}
291
292END_IGRAPHICS_NAMESPACE
293END_IPLUG_NAMESPACE
294
295#pragma mark -
296
297static sk_sp<SkFontMgr> SFontMgrFactory()
298{
299#if defined OS_MAC || defined OS_IOS
300 return SkFontMgr_New_CoreText(nullptr);
301#elif defined OS_WIN
302 return SkFontMgr_New_DirectWrite();
303#else
304 #error "Not supported"
305#endif
306}
307
308bool gFontMgrFactoryCreated = false;
309
310sk_sp<SkFontMgr> SkFontMgrRefDefault()
311{
312 static std::once_flag flag;
313 static sk_sp<SkFontMgr> mgr;
314 std::call_once(flag, [] {
315 mgr = SFontMgrFactory();
316 gFontMgrFactoryCreated = true;
317 });
318 return mgr;
319}
320
321#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
322
323bool gSkUnicodeCreated = false;
324
325sk_sp<SkUnicode> GetUnicode()
326{
327 static std::once_flag flag;
328 static sk_sp<SkUnicode> unicode;
329 std::call_once(flag, [] {
330 unicode = SkUnicodes::ICU::Make();
331 gSkUnicodeCreated = true;
332 });
333
334 if (!unicode)
335 {
336 DBGMSG("Could not load unicode data\n");
337 return nullptr;
338 }
339
340 return unicode;
341}
342#endif
343
344IGraphicsSkia::IGraphicsSkia(IGEditorDelegate& dlg, int w, int h, int fps, float scale)
345: IGraphics(dlg, w, h, fps, scale)
346{
347 mMainPath.setIsVolatile(true);
348
349#if defined IGRAPHICS_CPU
350 DBGMSG("IGraphics Skia CPU @ %i FPS\n", fps);
351#elif defined IGRAPHICS_METAL
352 DBGMSG("IGraphics Skia METAL @ %i FPS\n", fps);
353#elif defined IGRAPHICS_GL
354 DBGMSG("IGraphics Skia GL @ %i FPS\n", fps);
355#endif
356 StaticStorage<Font>::Accessor storage(sFontCache);
357 storage.Retain();
358
359#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
360 mFontCollection = sk_make_sp<skia::textlayout::FontCollection>();
361 mFontCollection->enableFontFallback();
362 mFontCollection->setDefaultFontManager(SkFontMgrRefDefault());
363#endif
364}
365
366IGraphicsSkia::~IGraphicsSkia()
367{
368 StaticStorage<Font>::Accessor storage(sFontCache);
369 storage.Release();
370}
371
373{
374 char extLower[32];
375 ToLower(extLower, ext);
376 return (strstr(extLower, "png") != nullptr) || (strstr(extLower, "jpg") != nullptr) || (strstr(extLower, "jpeg") != nullptr);
377}
378
379APIBitmap* IGraphicsSkia::LoadAPIBitmap(const char* fileNameOrResID, int scale, EResourceLocation location, const char* ext)
380{
381//#ifdef OS_IOS
382// if (location == EResourceLocation::kPreloadedTexture)
383// {
384// assert(0 && "SKIA does not yet load KTX textures");
385// GrMtlTextureInfo textureInfo;
386// textureInfo.fTexture.retain((void*)(gTextureMap[fileNameOrResID]));
387// id<MTLTexture> texture = (id<MTLTexture>) textureInfo.fTexture.get();
388//
389// MTLPixelFormat pixelFormat = texture.pixelFormat;
390//
391// auto grBackendTexture = GrBackendTexture(texture.width, texture.height, GrMipMapped::kNo, textureInfo);
392//
393// sk_sp<SkImage> image = SkImage::MakeFromTexture(mGrContext.get(), grBackendTexture, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, kOpaque_SkAlphaType, nullptr);
394// return new Bitmap(image, scale);
395// }
396// else
397//#endif
398#ifdef OS_WIN
399 if (location == EResourceLocation::kWinBinary)
400 {
401 int size = 0;
402 const void* pData = LoadWinResource(fileNameOrResID, ext, size, GetWinModuleHandle());
403 return new Bitmap(pData, size, scale);
404 }
405 else
406#endif
407 return new Bitmap(fileNameOrResID, scale);
408}
409
410APIBitmap* IGraphicsSkia::LoadAPIBitmap(const char* name, const void* pData, int dataSize, int scale)
411{
412 return new Bitmap(pData, dataSize, scale);
413}
414
416{
417#if defined IGRAPHICS_GL
418#if defined OS_MAC
419 auto glInterface = GrGLInterfaces::MakeMac();
420#elif defined OS_WIN
421 auto glInterface = GrGLInterfaces::MakeWin();
422#endif
423 mGrContext = GrDirectContexts::MakeGL(glInterface);
424#elif defined IGRAPHICS_METAL
425 CAMetalLayer* pMTLLayer = (CAMetalLayer*) pContext;
426 id<MTLDevice> device = pMTLLayer.device;
427 id<MTLCommandQueue> commandQueue = [device newCommandQueue];
428 GrMtlBackendContext backendContext = {};
429 backendContext.fDevice.retain((__bridge GrMTLHandle) device);
430 backendContext.fQueue.retain((__bridge GrMTLHandle) commandQueue);
431 mGrContext = GrDirectContexts::MakeMetal(backendContext);
432 mMTLDevice = (void*) device;
433 mMTLCommandQueue = (void*) commandQueue;
434 mMTLLayer = pContext;
435#endif
436
437 DrawResize();
438}
439
441{
443
444#if defined IGRAPHICS_GL
445 mSurface = nullptr;
446 mScreenSurface = nullptr;
447 mGrContext = nullptr;
448#elif defined IGRAPHICS_METAL
449 [(id<MTLCommandQueue>) mMTLCommandQueue release];
450 mMTLCommandQueue = nullptr;
451 mMTLLayer = nullptr;
452 mMTLDevice = nullptr;
453#endif
454}
455
457{
458 auto w = static_cast<int>(std::ceil(static_cast<float>(WindowWidth()) * GetScreenScale()));
459 auto h = static_cast<int>(std::ceil(static_cast<float>(WindowHeight()) * GetScreenScale()));
460
461#if defined IGRAPHICS_GL || defined IGRAPHICS_METAL
462 if (mGrContext.get())
463 {
464 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
465 mSurface = SkSurfaces::RenderTarget(mGrContext.get(), skgpu::Budgeted::kYes, info);
466 }
467#else
468 #ifdef OS_WIN
469 mSurface.reset();
470
471 const size_t bmpSize = sizeof(BITMAPINFOHEADER) + (w * h * sizeof(uint32_t));
472 mSurfaceMemory.Resize(bmpSize);
473 BITMAPINFO* bmpInfo = reinterpret_cast<BITMAPINFO*>(mSurfaceMemory.Get());
474 ZeroMemory(bmpInfo, sizeof(BITMAPINFO));
475 bmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
476 bmpInfo->bmiHeader.biWidth = w;
477 bmpInfo->bmiHeader.biHeight = -h; // negative means top-down bitmap. Skia draws top-down.
478 bmpInfo->bmiHeader.biPlanes = 1;
479 bmpInfo->bmiHeader.biBitCount = 32;
480 bmpInfo->bmiHeader.biCompression = BI_RGB;
481 void* pixels = bmpInfo->bmiColors;
482
483 SkImageInfo info = SkImageInfo::Make(w, h, kN32_SkColorType, kPremul_SkAlphaType, nullptr);
484 mSurface = SkSurfaces::WrapPixels(info, pixels, sizeof(uint32_t) * w);
485 #else
486 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
487 mSurface = SkSurfaces::Raster(info);
488 #endif
489#endif
490 if (mSurface)
491 {
492 mCanvas = mSurface->getCanvas();
493 mCanvas->save();
494 }
495}
496
498{
499#if defined IGRAPHICS_GL
500 if (mGrContext.get())
501 {
502 int width = WindowWidth() * GetScreenScale();
503 int height = WindowHeight() * GetScreenScale();
504
505 // Bind to the current main framebuffer
506 int fbo = 0, samples = 0, stencilBits = 0;
507 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
508 glGetIntegerv(GL_SAMPLES, &samples);
509#ifdef IGRAPHICS_GL3
510 glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencilBits);
511#else
512 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
513#endif
514
515 GrGLFramebufferInfo fbInfo;
516 fbInfo.fFBOID = fbo;
517 fbInfo.fFormat = 0x8058;
518
519 auto backendRT = GrBackendRenderTargets::MakeGL(width, height, samples, stencilBits, fbInfo);
520
521 mScreenSurface = SkSurfaces::WrapBackendRenderTarget(mGrContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, nullptr, nullptr);
522 assert(mScreenSurface);
523 }
524#elif defined IGRAPHICS_METAL
525 if (mGrContext.get())
526 {
527 int width = WindowWidth() * GetScreenScale();
528 int height = WindowHeight() * GetScreenScale();
529
530 id<CAMetalDrawable> drawable = [(CAMetalLayer*) mMTLLayer nextDrawable];
531
532 GrMtlTextureInfo fbInfo;
533 fbInfo.fTexture.retain((const void*)(drawable.texture));
534 auto backendRT = GrBackendRenderTargets::MakeMtl(width, height, fbInfo);
535 mScreenSurface = SkSurfaces::WrapBackendRenderTarget(mGrContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, nullptr, nullptr);
536
537 mMTLDrawable = (void*) drawable;
538 assert(mScreenSurface);
539 }
540#endif
541
543}
544
546{
547#ifdef IGRAPHICS_CPU
548 #if defined OS_MAC || defined OS_IOS
549 SkPixmap pixmap;
550 mSurface->peekPixels(&pixmap);
551 SkBitmap bmp;
552 bmp.installPixels(pixmap);
553 CGContext* pCGContext = (CGContextRef) GetPlatformContext();
554 CGContextSaveGState(pCGContext);
555 CGContextScaleCTM(pCGContext, 1.0 / GetScreenScale(), 1.0 / GetScreenScale());
556 SkCGDrawBitmap(pCGContext, bmp, 0, 0);
557 CGContextRestoreGState(pCGContext);
558 #elif defined OS_WIN
559 auto w = WindowWidth() * GetScreenScale();
560 auto h = WindowHeight() * GetScreenScale();
561 BITMAPINFO* bmpInfo = reinterpret_cast<BITMAPINFO*>(mSurfaceMemory.Get());
562 HWND hWnd = (HWND) GetWindow();
563 PAINTSTRUCT ps;
564 HDC hdc = BeginPaint(hWnd, &ps);
565 StretchDIBits(hdc, 0, 0, w, h, 0, 0, w, h, bmpInfo->bmiColors, bmpInfo, DIB_RGB_COLORS, SRCCOPY);
566 ReleaseDC(hWnd, hdc);
567 EndPaint(hWnd, &ps);
568 #else
569 #error NOT IMPLEMENTED
570 #endif
571#else // GPU
572 mSurface->draw(mScreenSurface->getCanvas(), 0.0, 0.0, nullptr);
573
574 if (auto dContext = GrAsDirectContext(mScreenSurface->getCanvas()->recordingContext())) {
575 dContext->flushAndSubmit();
576 }
577
578 #ifdef IGRAPHICS_METAL
579 id<MTLCommandBuffer> commandBuffer = [(id<MTLCommandQueue>) mMTLCommandQueue commandBuffer];
580 commandBuffer.label = @"Present";
581
582 [commandBuffer presentDrawable:(id<CAMetalDrawable>) mMTLDrawable];
583 [commandBuffer commit];
584 #endif
585#endif
586}
587
588void IGraphicsSkia::DrawBitmap(const IBitmap& bitmap, const IRECT& dest, int srcX, int srcY, const IBlend* pBlend)
589{
590 SkPaint p;
591
592 p.setAntiAlias(true);
593 p.setBlendMode(SkiaBlendMode(pBlend));
594 if (pBlend)
595 p.setAlpha(Clip(static_cast<int>(pBlend->mWeight * 255), 0, 255));
596
597 SkiaDrawable* image = bitmap.GetAPIBitmap()->GetBitmap();
598
599 double scale1 = 1.0 / (bitmap.GetScale() * bitmap.GetDrawScale());
600 double scale2 = bitmap.GetScale() * bitmap.GetDrawScale();
601
602 mCanvas->save();
603 mCanvas->clipRect(SkiaRect(dest));
604 mCanvas->translate(dest.L, dest.T);
605 mCanvas->scale(scale1, scale1);
606 mCanvas->translate(-srcX * scale2, -srcY * scale2);
607
608#ifdef IGRAPHICS_CPU
609 auto samplingOptions = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
610#else
611 auto samplingOptions = SkSamplingOptions(SkCubicResampler::Mitchell());
612#endif
613
614 if (image->mIsSurface)
615 image->mSurface->draw(mCanvas, 0.0, 0.0, samplingOptions, &p);
616 else
617 mCanvas->drawImage(image->mImage, 0.0, 0.0, samplingOptions, &p);
618
619 mCanvas->restore();
620}
621
622void IGraphicsSkia::PathArc(float cx, float cy, float r, float a1, float a2, EWinding winding)
623{
624 SkPath arc;
625 arc.setIsVolatile(true);
626
627 float sweep = (a2 - a1);
628
629 if (sweep >= 360.f || sweep <= -360.f)
630 {
631 arc.addCircle(cx, cy, r);
632 mMainPath.addPath(arc, mMatrix, SkPath::kAppend_AddPathMode);
633 }
634 else
635 {
636 if (winding == EWinding::CW)
637 {
638 while (sweep < 0)
639 sweep += 360.f;
640 }
641 else
642 {
643 while (sweep > 0)
644 sweep -= 360.f;
645 }
646
647 arc.arcTo(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, sweep, false);
648 mMainPath.addPath(arc, mMatrix, SkPath::kExtend_AddPathMode);
649 }
650}
651
653{
654 SkBitmap bitmap;
655 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
656 mCanvas->readPixels(bitmap, x, y);
657 auto color = bitmap.getColor(0,0);
658 return IColor(SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
659}
660
661bool IGraphicsSkia::LoadAPIFont(const char* fontID, const PlatformFontPtr& font)
662{
663 StaticStorage<Font>::Accessor storage(sFontCache);
664 Font* cached = storage.Find(fontID);
665
666 if (cached)
667 return true;
668
669 IFontDataPtr data = font->GetFontData();
670
671 if (data->IsValid())
672 {
673 auto wrappedData = SkData::MakeWithoutCopy(data->Get(), data->GetSize());
674 auto typeFace = SkFontMgrRefDefault()->makeFromData(wrappedData);
675 if (typeFace)
676 {
677 storage.Add(new Font(std::move(data), typeFace), fontID);
678 return true;
679 }
680 }
681
682 return false;
683}
684
685void IGraphicsSkia::PrepareAndMeasureText(const IText& text, const char* str, IRECT& r, double& x, double & y, SkFont& font) const
686{
687 SkFontMetrics metrics;
688 SkPaint paint;
689 //SkRect bounds;
690
691 StaticStorage<Font>::Accessor storage(sFontCache);
692 Font* pFont = storage.Find(text.mFont);
693
694 assert(pFont && "No font found - did you forget to load it?");
695
696 font.setTypeface(pFont->mTypeface);
697 font.setHinting(SkFontHinting::kSlight);
698 font.setForceAutoHinting(false);
699 font.setSubpixel(true);
700 font.setSize(text.mSize * pFont->mData->GetHeightEMRatio());
701
702 // Draw / measure
703 const double textWidth = font.measureText(str, strlen(str), SkTextEncoding::kUTF8, nullptr/* &bounds*/);
704 font.getMetrics(&metrics);
705
706 const double textHeight = text.mSize;
707 const double ascender = metrics.fAscent;
708 const double descender = metrics.fDescent;
709
710 switch (text.mAlign)
711 {
712 case EAlign::Near: x = r.L; break;
713 case EAlign::Center: x = r.MW() - (textWidth / 2.0); break;
714 case EAlign::Far: x = r.R - textWidth; break;
715 }
716
717 switch (text.mVAlign)
718 {
719 case EVAlign::Top: y = r.T - ascender; break;
720 case EVAlign::Middle: y = r.MH() - descender + (textHeight / 2.0); break;
721 case EVAlign::Bottom: y = r.B - descender; break;
722 }
723
724 r = IRECT((float) x, (float) y + ascender, (float) (x + textWidth), (float) (y + ascender + textHeight));
725}
726
727float IGraphicsSkia::DoMeasureText(const IText& text, const char* str, IRECT& bounds) const
728{
729 SkFont font;
730 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
731
732 IRECT r = bounds;
733 double x, y;
734 PrepareAndMeasureText(text, str, bounds, x, y, font);
735 DoMeasureTextRotation(text, r, bounds);
736 return bounds.W();
737}
738
739void IGraphicsSkia::DoDrawText(const IText& text, const char* str, const IRECT& bounds, const IBlend* pBlend)
740{
741 IRECT measured = bounds;
742
743 SkFont font;
744 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
745
746 double x, y;
747
748 PrepareAndMeasureText(text, str, measured, x, y, font);
750 DoTextRotation(text, bounds, measured);
751 SkPaint paint;
752 paint.setColor(SkiaColor(text.mFGColor, pBlend));
753 mCanvas->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint);
755}
756
757void IGraphicsSkia::PathStroke(const IPattern& pattern, float thickness, const IStrokeOptions& options, const IBlend* pBlend)
758{
759 SkPaint paint = SkiaPaint(pattern, pBlend);
760 paint.setStyle(SkPaint::kStroke_Style);
761
762 switch (options.mCapOption)
763 {
764 case ELineCap::Butt: paint.setStrokeCap(SkPaint::kButt_Cap); break;
765 case ELineCap::Round: paint.setStrokeCap(SkPaint::kRound_Cap); break;
766 case ELineCap::Square: paint.setStrokeCap(SkPaint::kSquare_Cap); break;
767 }
768
769 switch (options.mJoinOption)
770 {
771 case ELineJoin::Miter: paint.setStrokeJoin(SkPaint::kMiter_Join); break;
772 case ELineJoin::Round: paint.setStrokeJoin(SkPaint::kRound_Join); break;
773 case ELineJoin::Bevel: paint.setStrokeJoin(SkPaint::kBevel_Join); break;
774 }
775
776 if (options.mDash.GetCount())
777 {
778 // N.B. support odd counts by reading the array twice
779 int dashCount = options.mDash.GetCount();
780 int dashMax = dashCount & 1 ? dashCount * 2 : dashCount;
781 float dashArray[16];
782
783 for (int i = 0; i < dashMax; i += 2)
784 {
785 dashArray[i + 0] = options.mDash.GetArray()[i % dashCount];
786 dashArray[i + 1] = options.mDash.GetArray()[(i + 1) % dashCount];
787 }
788
789 paint.setPathEffect(SkDashPathEffect::Make(dashArray, dashMax, options.mDash.GetOffset()));
790 }
791
792 paint.setStrokeWidth(thickness);
793 paint.setStrokeMiter(options.mMiterLimit);
794
795 RenderPath(paint);
796
797 if (!options.mPreserve)
798 mMainPath.reset();
799}
800
801void IGraphicsSkia::PathFill(const IPattern& pattern, const IFillOptions& options, const IBlend* pBlend)
802{
803 SkPaint paint = SkiaPaint(pattern, pBlend);
804 paint.setStyle(SkPaint::kFill_Style);
805
806 if (options.mFillRule == EFillRule::Winding)
807 mMainPath.setFillType(SkPathFillType::kWinding);
808 else
809 mMainPath.setFillType(SkPathFillType::kEvenOdd);
810
811 RenderPath(paint);
812
813 if (!options.mPreserve)
814 mMainPath.reset();
815}
816
817#ifdef IGRAPHICS_DRAWFILL_DIRECT
818void IGraphicsSkia::DrawRect(const IColor& color, const IRECT& bounds, const IBlend* pBlend, float thickness)
819{
820 auto paint = SkiaPaint(color, pBlend);
821 paint.setStyle(SkPaint::Style::kStroke_Style);
822 paint.setStrokeWidth(thickness);
823 mCanvas->drawRect(SkiaRect(bounds), paint);
824}
825
826void IGraphicsSkia::DrawRoundRect(const IColor& color, const IRECT& bounds, float cornerRadius, const IBlend* pBlend, float thickness)
827{
828 auto paint = SkiaPaint(color, pBlend);
829 paint.setStyle(SkPaint::Style::kStroke_Style);
830 paint.setStrokeWidth(thickness);
831 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
832}
833
834void IGraphicsSkia::DrawArc(const IColor& color, float cx, float cy, float r, float a1, float a2, const IBlend* pBlend, float thickness)
835{
836 auto paint = SkiaPaint(color, pBlend);
837 paint.setStyle(SkPaint::Style::kStroke_Style);
838 paint.setStrokeWidth(thickness);
839 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1), false, paint);
840}
841
842void IGraphicsSkia::DrawCircle(const IColor& color, float cx, float cy, float r, const IBlend* pBlend, float thickness)
843{
844 auto paint = SkiaPaint(color, pBlend);
845 paint.setStyle(SkPaint::Style::kStroke_Style);
846 paint.setStrokeWidth(thickness);
847 mCanvas->drawCircle(cx, cy, r, paint);
848}
849
850void IGraphicsSkia::DrawEllipse(const IColor& color, const IRECT& bounds, const IBlend* pBlend, float thickness)
851{
852 auto paint = SkiaPaint(color, pBlend);
853 paint.setStyle(SkPaint::Style::kStroke_Style);
854 paint.setStrokeWidth(thickness);
855 mCanvas->drawOval(SkiaRect(bounds), paint);
856}
857
858void IGraphicsSkia::FillRect(const IColor& color, const IRECT& bounds, const IBlend* pBlend)
859{
860 auto paint = SkiaPaint(color, pBlend);
861 paint.setStyle(SkPaint::Style::kFill_Style);
862 mCanvas->drawRect(SkiaRect(bounds), paint);
863}
864
865void IGraphicsSkia::FillRoundRect(const IColor& color, const IRECT& bounds, float cornerRadius, const IBlend* pBlend)
866{
867 auto paint = SkiaPaint(color, pBlend);
868 paint.setStyle(SkPaint::Style::kFill_Style);
869 mCanvas->drawRoundRect(SkiaRect(bounds), cornerRadius, cornerRadius, paint);
870}
871
872void IGraphicsSkia::FillArc(const IColor& color, float cx, float cy, float r, float a1, float a2, const IBlend* pBlend)
873{
874 auto paint = SkiaPaint(color, pBlend);
875 paint.setStyle(SkPaint::Style::kFill_Style);
876 mCanvas->drawArc(SkRect::MakeLTRB(cx - r, cy - r, cx + r, cy + r), a1 - 90.f, (a2 - a1), true, paint);
877}
878
879void IGraphicsSkia::FillCircle(const IColor& color, float cx, float cy, float r, const IBlend* pBlend)
880{
881 auto paint = SkiaPaint(color, pBlend);
882 paint.setStyle(SkPaint::Style::kFill_Style);
883 mCanvas->drawCircle(cx, cy, r, paint);
884}
885
886void IGraphicsSkia::FillEllipse(const IColor& color, const IRECT& bounds, const IBlend* pBlend)
887{
888 auto paint = SkiaPaint(color, pBlend);
889 paint.setStyle(SkPaint::Style::kFill_Style);
890 mCanvas->drawOval(SkiaRect(bounds), paint);
891}
892#endif
893
894void IGraphicsSkia::RenderPath(SkPaint& paint)
895{
896 SkMatrix invMatrix;
897
898 if (!mMatrix.isIdentity() && mMatrix.invert(&invMatrix))
899 {
900 SkPath path;
901 path.setIsVolatile(true);
902 mMainPath.transform(invMatrix, &path);
903 mCanvas->drawPath(path, paint);
904 }
905 else
906 {
907 mCanvas->drawPath(mMainPath, paint);
908 }
909}
910
911void IGraphicsSkia::PathTransformSetMatrix(const IMatrix& m)
912{
913 double xTranslate = 0.0;
914 double yTranslate = 0.0;
915
916 if (!mCanvas)
917 return;
918
919 if (!mLayers.empty())
920 {
921 IRECT bounds = mLayers.top()->Bounds();
922
923 xTranslate = -bounds.L;
924 yTranslate = -bounds.T;
925 }
926
927 mMatrix = SkMatrix::MakeAll(m.mXX, m.mXY, m.mTX, m.mYX, m.mYY, m.mTY, 0, 0, 1);
928 auto scale = GetTotalScale();
929 SkMatrix globalMatrix = SkMatrix::Scale(scale, scale);
930 mClipMatrix = SkMatrix();
931 mFinalMatrix = mMatrix;
932 globalMatrix.preTranslate(xTranslate, yTranslate);
933 mClipMatrix.postConcat(globalMatrix);
934 mFinalMatrix.postConcat(globalMatrix);
935 mCanvas->setMatrix(mFinalMatrix);
936}
937
938void IGraphicsSkia::SetClipRegion(const IRECT& r)
939{
940 mCanvas->restoreToCount(0);
941 mCanvas->save();
942 mCanvas->setMatrix(mClipMatrix);
943 mCanvas->clipRect(SkiaRect(r));
944 mCanvas->setMatrix(mFinalMatrix);
945}
946
947APIBitmap* IGraphicsSkia::CreateAPIBitmap(int width, int height, float scale, double drawScale, bool cacheable)
948{
949 sk_sp<SkSurface> surface;
950 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
951
952 #ifndef IGRAPHICS_CPU
953 if (cacheable)
954 {
955 surface = SkSurfaces::Raster(info);
956 }
957 else
958 {
959 surface = SkSurfaces::RenderTarget(mGrContext.get(), skgpu::Budgeted::kYes, info);
960 }
961 #else
962 surface = SkSurfaces::Raster(info);
963 #endif
964
965 surface->getCanvas()->save();
966
967 return new Bitmap(std::move(surface), width, height, scale, drawScale);
968}
969
971{
972 mCanvas = mLayers.empty() ? mSurface->getCanvas() : mLayers.top()->GetAPIBitmap()->GetBitmap()->mSurface->getCanvas();
973}
974
975static size_t CalcRowBytes(int width)
976{
977 width = ((width + 7) & (-8));
978 return width * sizeof(uint32_t);
979}
980
981void IGraphicsSkia::GetLayerBitmapData(const ILayerPtr& layer, RawBitmapData& data)
982{
983 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
984 size_t rowBytes = CalcRowBytes(pDrawable->mSurface->width());
985 int size = pDrawable->mSurface->height() * static_cast<int>(rowBytes);
986
987 data.Resize(size);
988
989 if (data.GetSize() >= size)
990 {
991 SkImageInfo info = SkImageInfo::MakeN32Premul(pDrawable->mSurface->width(), pDrawable->mSurface->height());
992 pDrawable->mSurface->readPixels(info, data.Get(), rowBytes, 0, 0);
993 }
994}
995
996void IGraphicsSkia::ApplyShadowMask(ILayerPtr& layer, RawBitmapData& mask, const IShadow& shadow)
997{
998 SkiaDrawable* pDrawable = layer->GetAPIBitmap()->GetBitmap();
999 int width = pDrawable->mSurface->width();
1000 int height = pDrawable->mSurface->height();
1001 size_t rowBytes = CalcRowBytes(width);
1002 double scale = layer->GetAPIBitmap()->GetDrawScale() * layer->GetAPIBitmap()->GetScale();
1003
1004 SkCanvas* pCanvas = pDrawable->mSurface->getCanvas();
1005
1006 SkMatrix m;
1007 m.reset();
1008
1009 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
1010 SkPixmap pixMap(info, mask.Get(), rowBytes);
1011 sk_sp<SkImage> image = SkImages::RasterFromPixmap(pixMap, nullptr, nullptr);
1012 sk_sp<SkImage> foreground;
1013
1014 // Copy the foreground if needed
1015
1016 if (shadow.mDrawForeground)
1017 foreground = pDrawable->mSurface->makeImageSnapshot();
1018
1019 pCanvas->clear(SK_ColorTRANSPARENT);
1020
1021 IBlend blend(EBlend::Default, shadow.mOpacity);
1022 pCanvas->setMatrix(m);
1023 pCanvas->drawImage(image.get(), shadow.mXOffset * scale, shadow.mYOffset * scale);
1024 m = SkMatrix::Scale(scale, scale);
1025 pCanvas->setMatrix(m);
1026 pCanvas->translate(-layer->Bounds().L, -layer->Bounds().T);
1027 SkPaint p = SkiaPaint(shadow.mPattern, &blend);
1028 p.setBlendMode(SkBlendMode::kSrcIn);
1029 pCanvas->drawPaint(p);
1030
1031 if (shadow.mDrawForeground)
1032 {
1033 m.reset();
1034 pCanvas->setMatrix(m);
1035 pCanvas->drawImage(foreground.get(), 0.0, 0.0);
1036 }
1037}
1038
1039void IGraphicsSkia::DrawFastDropShadow(const IRECT& innerBounds, const IRECT& outerBounds, float xyDrop, float roundness, float blur, IBlend* pBlend)
1040{
1041 SkRect r = SkiaRect(innerBounds.GetTranslated(xyDrop, xyDrop));
1042
1043 SkPaint paint = SkiaPaint(COLOR_BLACK_DROP_SHADOW, pBlend);
1044 paint.setStyle(SkPaint::Style::kFill_Style);
1045
1046 paint.setMaskFilter(SkMaskFilter::MakeBlur(kSolid_SkBlurStyle, blur * 0.5)); // 0.5 seems to match nanovg
1047 mCanvas->drawRoundRect(r, roundness, roundness, paint);
1048}
1049
1050void IGraphicsSkia::DrawMultiLineText(const IText& text, const char* str, const IRECT& bounds, const IBlend* pBlend)
1051{
1052#if !defined IGRAPHICS_NO_SKIA_SKPARAGRAPH
1053 using namespace skia::textlayout;
1054
1055 auto ConvertTextAlign = [](EAlign align) {
1056 switch (align)
1057 {
1058 case EAlign::Near: return TextAlign::kLeft;
1059 case EAlign::Center: return TextAlign::kCenter;
1060 case EAlign::Far: return TextAlign::kRight;
1061 default: return TextAlign::kLeft;
1062 }
1063 };
1064
1065 ParagraphStyle paragraphStyle;
1066 paragraphStyle.setTextAlign(ConvertTextAlign(text.mAlign));
1067
1068 auto builder = ParagraphBuilder::make(paragraphStyle, mFontCollection, GetUnicode());
1069
1070 assert(builder && "Paragraph Builder couldn't be created");
1071
1072 TextStyle textStyle;
1073 textStyle.setColor(SkiaColor(text.mFGColor, pBlend));
1074
1075 std::string fontFamily = text.mFont;
1076
1077 size_t pos = fontFamily.find('-');
1078 if (pos != std::string::npos)
1079 {
1080 fontFamily = fontFamily.substr(0, pos);
1081 }
1082
1083 textStyle.setFontFamilies({SkString(fontFamily)});
1084 textStyle.setFontSize(text.mSize * 0.9);
1085 textStyle.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight,
1086 SkFontStyle::kNormal_Width,
1087 SkFontStyle::kUpright_Slant));
1088
1089 builder->pushStyle(textStyle);
1090 builder->addText(str);
1091 builder->pop();
1092
1093 auto paragraph = builder->Build();
1094
1095 paragraph->layout(bounds.W());
1096
1097 float yOffset = 0;
1098 switch (text.mVAlign)
1099 {
1100 case EVAlign::Top:
1101 yOffset = 0;
1102 break;
1103 case EVAlign::Middle:
1104 yOffset = (bounds.H() - paragraph->getHeight()) / 2;
1105 break;
1106 case EVAlign::Bottom:
1107 yOffset = bounds.H() - paragraph->getHeight();
1108 break;
1109 }
1110
1111 mCanvas->save();
1112 mCanvas->translate(bounds.L, bounds.T + yOffset);
1113 paragraph->paint(mCanvas, 0, 0);
1114 mCanvas->restore();
1115#else
1116 DrawText(text, str, bounds, pBlend);
1117#endif
1118}
1119
1121{
1122#ifdef IGRAPHICS_CPU
1123 return "SKIA | CPU";
1124#elif defined IGRAPHICS_GL2
1125 return "SKIA | GL2";
1126#elif defined IGRAPHICS_GL3
1127 return "SKIA | GL3";
1128#elif defined IGRAPHICS_METAL
1129 return "SKIA | Metal";
1130#endif
1131}
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
float GetScale() const
APIBitmap * GetAPIBitmap() const
An editor delegate base class that uses IGraphics for the UI.
The lowest level base class of an IGraphics context.
Definition: IGraphics.h:86
virtual void DrawRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0, float thickness=1.f)
Draw a rectangle to the graphics context.
Definition: IGraphics.cpp:2508
virtual void FillEllipse(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill an ellipse within a rectangular region of the graphics context.
Definition: IGraphics.cpp:2624
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.
Definition: IGraphics.cpp:2559
void DrawText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend=0)
Draw some text to the graphics context in a specific rectangle.
Definition: IGraphics.cpp:678
float GetTotalScale() const
Gets the combined draw and screen/display scaling factor.
Definition: IGraphics.h:1118
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.
Definition: IGraphics.cpp:2515
void DoMeasureTextRotation(const IText &text, const IRECT &bounds, IRECT &rect) const
Definition: IGraphics.cpp:2238
int WindowWidth() const
Gets the width of the graphics context including draw scaling.
Definition: IGraphics.h:1094
void PathTransformRestore()
Restore the affine transform of the current path, to the previously saved state.
Definition: IGraphics.cpp:2719
virtual void FillRect(const IColor &color, const IRECT &bounds, const IBlend *pBlend=0)
Fill a rectangular region of the graphics context with a color.
Definition: IGraphics.cpp:2580
void * GetPlatformContext()
Get the platform level draw context - an HDC or CGContextRef.
Definition: IGraphics.h:935
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.
Definition: IGraphics.cpp:2536
void RemoveAllControls()
Removes all regular IControls from the control list, as well as special controls (frees memory).
Definition: IGraphics.cpp:194
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.
Definition: IGraphics.cpp:2543
virtual void FillRoundRect(const IColor &color, const IRECT &bounds, float cornerRadius=5.f, const IBlend *pBlend=0)
Fill a rounded rectangle with a color.
Definition: IGraphics.cpp:2587
virtual void * GetWinModuleHandle()
Definition: IGraphics.h:926
float GetScreenScale() const
Gets the screen/display scaling factor, e.g.
Definition: IGraphics.h:1110
void PathTransformSave()
Save the current affine transform of the current path.
Definition: IGraphics.cpp:2714
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.
Definition: IGraphics.cpp:2608
int WindowHeight() const
Gets the height of the graphics context including draw scaling.
Definition: IGraphics.h:1098
virtual void BeginFrame()
Called at the beginning of drawing.
Definition: IGraphics.cpp:875
virtual void FillCircle(const IColor &color, float cx, float cy, float r, const IBlend *pBlend=0)
Fill a circle with a color.
Definition: IGraphics.cpp:2617
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 DrawMultiLineText(const IText &text, const char *str, const IRECT &bounds, const IBlend *pBlend) override
Draw some multi-line text to the graphics context in a specific rectangle (NanoVG only)
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)
int NStops() const
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.
float MH() const
float W() const
float H() const
float MW() const
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,...