You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.4KB

  1. #include "widgets.hpp"
  2. #include "gui.hpp"
  3. #include <GL/glew.h>
  4. #include "../ext/nanovg/src/nanovg_gl.h"
  5. #include "../ext/nanovg/src/nanovg_gl_utils.h"
  6. #include "../ext/osdialog/osdialog.h"
  7. namespace rack {
  8. struct FramebufferWidget::Internal {
  9. NVGLUframebuffer *fb = NULL;
  10. Rect box;
  11. ~Internal() {
  12. setFramebuffer(NULL);
  13. }
  14. void setFramebuffer(NVGLUframebuffer *fb) {
  15. if (this->fb)
  16. nvgluDeleteFramebuffer(this->fb);
  17. this->fb = fb;
  18. }
  19. };
  20. FramebufferWidget::FramebufferWidget() {
  21. internal = new Internal();
  22. }
  23. FramebufferWidget::~FramebufferWidget() {
  24. delete internal;
  25. }
  26. void FramebufferWidget::step() {
  27. // Step children before rendering
  28. Widget::step();
  29. // Render the scene to the framebuffer if dirty
  30. if (dirty) {
  31. internal->box.pos = Vec(0, 0);
  32. internal->box.size = box.size;
  33. internal->box.size = Vec(ceilf(internal->box.size.x), ceilf(internal->box.size.y));
  34. Vec fbSize = internal->box.size.mult(gPixelRatio * oversample);
  35. // assert(fbSize.isFinite());
  36. // Reject zero area size
  37. if (fbSize.x <= 0.0 || fbSize.y <= 0.0)
  38. return;
  39. // Delete old one first to free up GPU memory
  40. internal->setFramebuffer(NULL);
  41. NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
  42. if (!fb)
  43. return;
  44. internal->setFramebuffer(fb);
  45. nvgluBindFramebuffer(fb);
  46. glViewport(0.0, 0.0, fbSize.x, fbSize.y);
  47. glClearColor(0.0, 0.0, 0.0, 0.0);
  48. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  49. nvgBeginFrame(gVg, fbSize.x, fbSize.y, gPixelRatio * oversample);
  50. nvgScale(gVg, gPixelRatio * oversample, gPixelRatio * oversample);
  51. Widget::draw(gVg);
  52. nvgEndFrame(gVg);
  53. nvgluBindFramebuffer(NULL);
  54. dirty = false;
  55. }
  56. }
  57. void FramebufferWidget::draw(NVGcontext *vg) {
  58. if (!internal->fb) {
  59. // Bypass framebuffer cache entirely
  60. // Widget::draw(vg);
  61. return;
  62. }
  63. // Draw framebuffer image
  64. nvgBeginPath(vg);
  65. nvgRect(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y);
  66. NVGpaint paint = nvgImagePattern(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y, 0.0, internal->fb->image, 1.0);
  67. nvgFillPaint(vg, paint);
  68. nvgFill(vg);
  69. // For debugging bounding box of framebuffer image
  70. // nvgFillColor(vg, nvgRGBA(255, 0, 0, 64));
  71. // nvgFill(vg);
  72. }
  73. int FramebufferWidget::getImageHandle() {
  74. if (!internal->fb)
  75. return -1;
  76. return internal->fb->image;
  77. }
  78. } // namespace rack