@@ -202,8 +202,8 @@ void NVGSurface::detachContext()
202202void NVGSurface::updateBufferSize ()
203203{
204204 float pixelScale = getRenderScale ();
205- int scaledWidth = getWidth () * pixelScale;
206- int scaledHeight = getHeight () * pixelScale;
205+ int scaledWidth = getWidth () * pixelScale + doubleCnvMargin ;
206+ int scaledHeight = getHeight () * pixelScale + doubleCnvMargin ;
207207
208208 if (fbWidth != scaledWidth || fbHeight != scaledHeight || !invalidFBO) {
209209 if (invalidFBO)
@@ -216,11 +216,12 @@ void NVGSurface::updateBufferSize()
216216
217217 if (quickCanvasBlurFBO)
218218 nvgDeleteFramebuffer (quickCanvasBlurFBO);
219+ // The blur frame buffer is Float16 RGB (no alpha) with two colour attachments for multi-pass optimized blurring
219220 quickCanvasBlurFBO = nvgCreateFramebuffer (nvg, scaledWidth, scaledHeight, NVG_IMAGE_PREMULTIPLIED | NVG_IMAGE_FLOAT | NVG_DOUBLE_COLOUR_ATTACH);
220221
221222 fbWidth = scaledWidth;
222223 fbHeight = scaledHeight;
223- invalidArea = getLocalBounds ();
224+ invalidArea = getLocalBounds (). expanded ( 32 ) ;
224225 }
225226}
226227
@@ -308,12 +309,12 @@ void NVGSurface::resized()
308309
309310void NVGSurface::invalidateAll ()
310311{
311- invalidArea = invalidArea.getUnion (getLocalBounds ());
312+ invalidArea = invalidArea.getUnion (getLocalBounds (). expanded (cnvMargin). translated (cnvMargin, cnvMargin) );
312313}
313314
314315void NVGSurface::invalidateArea (Rectangle<int > area)
315316{
316- invalidArea = invalidArea.getUnion (area);
317+ invalidArea = invalidArea.getUnion (area. translated (cnvMargin, cnvMargin) );
317318}
318319
319320void NVGSurface::render ()
@@ -368,15 +369,15 @@ void NVGSurface::render()
368369
369370 updateBufferSize ();
370371
371- invalidArea = invalidArea.getIntersection (getLocalBounds ());
372+ invalidArea = invalidArea.getIntersection (getLocalBounds (). translated (cnvMargin, cnvMargin). expanded (cnvMargin) );
372373
373374 if (auto * cnv = editor->getPluginModeCanvas ()) {
374- cnv->updateFramebuffers (nvg, cnv->getLocalBounds ());
375+ cnv->updateFramebuffers (nvg, cnv->getLocalBounds (). expanded (cnvMargin) );
375376 } else {
376377 for (auto * cnv : editor->getTabComponent ().getVisibleCanvases ()) {
377- cnv->updateFramebuffers (nvg, cnv->getLocalBounds ());
378+ cnv->updateFramebuffers (nvg, cnv->getLocalBounds (). expanded (cnvMargin) );
378379 if (cnv->quickCanvas ) {
379- cnv->quickCanvas ->updateFramebuffers (nvg, cnv->getLocalBounds ());
380+ cnv->quickCanvas ->updateFramebuffers (nvg, cnv->getLocalBounds (). expanded (cnvMargin) );
380381 }
381382 }
382383 }
@@ -386,48 +387,60 @@ void NVGSurface::render()
386387 if (!invalidArea.isEmpty ()) {
387388 // Draw only the invalidated region on top of framebuffer
388389 nvgBindFramebuffer (invalidFBO);
389- nvgViewport (0 , 0 , viewWidth, viewHeight);
390+ nvgViewport (0 , 0 , viewWidth + doubleCnvMargin , viewHeight + doubleCnvMargin );
390391#if NANOVG_GL_IMPLEMENTATION
391392 glClear (GL_STENCIL_BUFFER_BIT);
392393#endif
393- nvgBeginFrame (nvg, getWidth () * desktopScale, getHeight () * desktopScale, devicePixelScale);
394+ nvgBeginFrame (nvg, getWidth () * desktopScale + doubleCnvMargin, getHeight () * desktopScale + doubleCnvMargin, devicePixelScale);
395+ nvgTranslate (nvg, cnvMargin, cnvMargin);
394396 nvgScale (nvg, desktopScale, desktopScale);
395397 doQuickCanvasPass = editor->renderArea (nvg, invalidArea);
398+
399+ // #define DEBUG_QUICKCANVAS_PAINT
400+ #ifdef DEBUG_QUICKCANVAS_PAINT
401+ nvgTranslate (nvg, -cnvMargin, -cnvMargin);
402+ Random random;
403+ nvgBeginPath (nvg);
404+ nvgFillColor (nvg, nvgRGBA (random.nextInt (256 ), random.nextInt (256 ), random.nextInt (256 ), 100 ));
405+ nvgFillRect (nvg, invalidArea.getX () * pixelScale, invalidArea.getY () * pixelScale, invalidArea.getWidth () * pixelScale, invalidArea.getHeight () * pixelScale);
406+ #endif
396407 nvgGlobalScissor (nvg, invalidArea.getX () * pixelScale, invalidArea.getY () * pixelScale, invalidArea.getWidth () * pixelScale, invalidArea.getHeight () * pixelScale);
408+
397409 nvgEndFrame (nvg);
398410
399411#if ENABLE_FPS_COUNT
400412 frameTimer->render (nvg, getWidth (), getHeight (), pixelScale);
401413#endif
402414
403- if (doQuickCanvasPass && !invalidArea. isEmpty () ) {
415+ if (doQuickCanvasPass) {
404416 for (auto cnv : editor->getTabComponent ().getSplitCanvasesQuickCanvases ()) {
417+ auto sX = cnv->getActiveViewport ()->getX ();
418+ auto sY = cnv->getActiveViewport ()->getY () - 30 ; // height of tabbar
419+ auto sW = cnv->getActiveViewport ()->getWidth ();
420+ auto sH = cnv->getActiveViewport ()->getHeight ();
421+ // Blur the current canvas invalidFBO
422+ nvgBindFramebuffer (quickCanvasBlurFBO);
423+ nvgBlitFramebuffer (nvg, invalidFBO, 0 , 0 , fbWidth, fbHeight, 0 , 0 , fbWidth, fbHeight);
424+
425+ // glScissor(sX, sY, sW, sH);
426+ glDisable (GL_SCISSOR_TEST);
427+ nvgBlurFramebuffer (nvg, quickCanvasBlurFBO, 0 , 0 , fbWidth, fbHeight, fbWidth, fbHeight, cnv->quickCanvasAlpha * getValue<float >(cnv->zoomScale ));
428+ glEnable (GL_SCISSOR_TEST);
405429
406430 nvgBindFramebuffer (quickCanvasFBO);
407431
408432 // Clear only the invalid region
409433 glClearColor (0 , 0 , 0 , 0 );
410434 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
411435
412- nvgBeginFrame (nvg, getWidth () * desktopScale, getHeight () * desktopScale, devicePixelScale);
436+ nvgBeginFrame (nvg, getWidth () * desktopScale + doubleCnvMargin, getHeight () * desktopScale + doubleCnvMargin, devicePixelScale);
437+ nvgTranslate (nvg, cnvMargin, cnvMargin);
413438 nvgScale (nvg, desktopScale, desktopScale);
414439 editor->renderArea (nvg, invalidArea, true );
415440 nvgGlobalScissor (nvg, invalidArea.getX () * pixelScale, invalidArea.getY () * pixelScale, invalidArea.getWidth () * pixelScale, invalidArea.getHeight () * pixelScale);
416441
417- // #define DEBUG_QUICKCANVAS_PAINT
418- #ifdef DEBUG_QUICKCANVAS_PAINT
419- Random random;
420- nvgBeginPath (nvg);
421- nvgFillColor (nvg, nvgRGBA (random.nextInt (256 ), random.nextInt (256 ), random.nextInt (256 ), 100 ));
422- nvgFillRect (nvg, invalidArea.getX () * pixelScale, invalidArea.getY () * pixelScale, invalidArea.getWidth () * pixelScale, invalidArea.getHeight () * pixelScale);
423- #endif
424442 nvgEndFrame (nvg);
425443
426- // Blur the current canvas invalidFBO
427- nvgBindFramebuffer (quickCanvasBlurFBO);
428- nvgBlitFramebuffer (nvg, invalidFBO, 0 , 0 , viewWidth, viewHeight, 0 , 0 , viewWidth, viewHeight);
429- nvgBlurFramebuffer (nvg, quickCanvasBlurFBO, fbWidth, fbHeight, cnv->quickCanvasAlpha * getValue<float >(cnv->zoomScale ));
430-
431444 nvgBindFramebuffer (quickCanvasBlurFBO);
432445 nvgViewport (0 , 0 , fbWidth, fbHeight);
433446 nvgBeginFrame (nvg, fbWidth, fbHeight, 1 );
@@ -451,10 +464,13 @@ void NVGSurface::render()
451464
452465 if (needsBufferSwap) {
453466 nvgBindFramebuffer (nullptr );
467+ glDisable (GL_SCISSOR_TEST);
454468 if (doQuickCanvasPass)
455- nvgBlitFramebuffer (nvg, quickCanvasBlurFBO, 0 , 0 , viewWidth, viewHeight, 0 , 0 , viewWidth, viewHeight);
469+ nvgBlitFramebuffer (nvg, quickCanvasBlurFBO, cnvMargin, -cnvMargin , viewWidth, viewHeight + doubleCnvMargin , 0 , 0 , viewWidth, viewHeight + doubleCnvMargin );
456470 else
457- nvgBlitFramebuffer (nvg, invalidFBO, 0 , 0 , viewWidth, viewHeight, 0 , 0 , viewWidth, viewHeight);
471+ nvgBlitFramebuffer (nvg, invalidFBO, cnvMargin, -cnvMargin, viewWidth, viewHeight + doubleCnvMargin, 0 , 0 , viewWidth, viewHeight + doubleCnvMargin);
472+
473+ glEnable (GL_SCISSOR_TEST);
458474
459475#ifdef NANOVG_GL_IMPLEMENTATION
460476 glContext->swapBuffers ();
0 commit comments