The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

218 lines
7.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. class OpenGLFrameBufferImage : public ImagePixelData
  21. {
  22. public:
  23. OpenGLFrameBufferImage (OpenGLContext& c, int w, int h)
  24. : ImagePixelData (Image::ARGB, w, h),
  25. context (c),
  26. pixelStride (4),
  27. lineStride (width * pixelStride)
  28. {
  29. }
  30. bool initialise()
  31. {
  32. if (! frameBuffer.initialise (context, width, height))
  33. return false;
  34. frameBuffer.clear (Colours::transparentBlack);
  35. return true;
  36. }
  37. std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
  38. {
  39. sendDataChangeMessage();
  40. return createOpenGLGraphicsContext (context, frameBuffer);
  41. }
  42. std::unique_ptr<ImageType> createType() const override { return std::make_unique<OpenGLImageType>(); }
  43. ImagePixelData::Ptr clone() override
  44. {
  45. std::unique_ptr<OpenGLFrameBufferImage> im (new OpenGLFrameBufferImage (context, width, height));
  46. if (! im->initialise())
  47. return ImagePixelData::Ptr();
  48. Image newImage (im.release());
  49. Graphics g (newImage);
  50. g.drawImageAt (Image (*this), 0, 0, false);
  51. return ImagePixelData::Ptr (newImage.getPixelData());
  52. }
  53. void initialiseBitmapData (Image::BitmapData& bitmapData, int x, int y, Image::BitmapData::ReadWriteMode mode) override
  54. {
  55. bitmapData.pixelFormat = pixelFormat;
  56. bitmapData.lineStride = lineStride;
  57. bitmapData.pixelStride = pixelStride;
  58. switch (mode)
  59. {
  60. case Image::BitmapData::writeOnly: DataReleaser<Dummy, Writer>::initialise (frameBuffer, bitmapData, x, y); break;
  61. case Image::BitmapData::readOnly: DataReleaser<Reader, Dummy> ::initialise (frameBuffer, bitmapData, x, y); break;
  62. case Image::BitmapData::readWrite: DataReleaser<Reader, Writer>::initialise (frameBuffer, bitmapData, x, y); break;
  63. default: jassertfalse; break;
  64. }
  65. if (mode != Image::BitmapData::readOnly)
  66. sendDataChangeMessage();
  67. }
  68. OpenGLContext& context;
  69. OpenGLFrameBuffer frameBuffer;
  70. private:
  71. int pixelStride, lineStride;
  72. struct Dummy
  73. {
  74. Dummy (OpenGLFrameBuffer&, int, int, int, int) noexcept {}
  75. static void read (OpenGLFrameBuffer&, Image::BitmapData& , int, int) noexcept {}
  76. static void write (const PixelARGB*) noexcept {}
  77. };
  78. struct Reader
  79. {
  80. static void read (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
  81. {
  82. frameBuffer.readPixels ((PixelARGB*) bitmapData.data,
  83. Rectangle<int> (x, frameBuffer.getHeight() - (y + bitmapData.height), bitmapData.width, bitmapData.height));
  84. verticalRowFlip ((PixelARGB*) bitmapData.data, bitmapData.width, bitmapData.height);
  85. }
  86. static void verticalRowFlip (PixelARGB* const data, const int w, const int h)
  87. {
  88. HeapBlock<PixelARGB> tempRow (w);
  89. auto rowSize = (size_t) w * sizeof (PixelARGB);
  90. for (int y = 0; y < h / 2; ++y)
  91. {
  92. PixelARGB* const row1 = data + y * w;
  93. PixelARGB* const row2 = data + (h - 1 - y) * w;
  94. memcpy (tempRow, row1, rowSize);
  95. memcpy (row1, row2, rowSize);
  96. memcpy (row2, tempRow, rowSize);
  97. }
  98. }
  99. };
  100. struct Writer
  101. {
  102. Writer (OpenGLFrameBuffer& fb, int x, int y, int w, int h) noexcept
  103. : frameBuffer (fb), area (x, y, w, h)
  104. {}
  105. void write (const PixelARGB* const data) const noexcept
  106. {
  107. HeapBlock<PixelARGB> invertedCopy (area.getWidth() * area.getHeight());
  108. auto rowSize = (size_t) area.getWidth() * sizeof (PixelARGB);
  109. for (int y = 0; y < area.getHeight(); ++y)
  110. memcpy (invertedCopy + area.getWidth() * y,
  111. data + area.getWidth() * (area.getHeight() - 1 - y), rowSize);
  112. frameBuffer.writePixels (invertedCopy, area);
  113. }
  114. OpenGLFrameBuffer& frameBuffer;
  115. const Rectangle<int> area;
  116. JUCE_DECLARE_NON_COPYABLE (Writer)
  117. };
  118. template <class ReaderType, class WriterType>
  119. struct DataReleaser : public Image::BitmapData::BitmapDataReleaser
  120. {
  121. DataReleaser (OpenGLFrameBuffer& fb, int x, int y, int w, int h)
  122. : data ((size_t) (w * h)),
  123. writer (fb, x, y, w, h)
  124. {}
  125. ~DataReleaser()
  126. {
  127. writer.write (data);
  128. }
  129. static void initialise (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
  130. {
  131. auto* r = new DataReleaser (frameBuffer, x, y, bitmapData.width, bitmapData.height);
  132. bitmapData.dataReleaser.reset (r);
  133. bitmapData.data = (uint8*) r->data.get();
  134. bitmapData.size = (size_t) bitmapData.width
  135. * (size_t) bitmapData.height
  136. * sizeof (PixelARGB);
  137. bitmapData.lineStride = (bitmapData.width * bitmapData.pixelStride + 3) & ~3;
  138. ReaderType::read (frameBuffer, bitmapData, x, y);
  139. }
  140. HeapBlock<PixelARGB> data;
  141. WriterType writer;
  142. };
  143. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLFrameBufferImage)
  144. };
  145. //==============================================================================
  146. OpenGLImageType::OpenGLImageType() {}
  147. OpenGLImageType::~OpenGLImageType() {}
  148. int OpenGLImageType::getTypeID() const
  149. {
  150. return 3;
  151. }
  152. ImagePixelData::Ptr OpenGLImageType::create (Image::PixelFormat, int width, int height, bool /*shouldClearImage*/) const
  153. {
  154. OpenGLContext* currentContext = OpenGLContext::getCurrentContext();
  155. jassert (currentContext != nullptr); // an OpenGL image can only be created when a valid context is active!
  156. std::unique_ptr<OpenGLFrameBufferImage> im (new OpenGLFrameBufferImage (*currentContext, width, height));
  157. if (! im->initialise())
  158. return ImagePixelData::Ptr();
  159. return *im.release();
  160. }
  161. OpenGLFrameBuffer* OpenGLImageType::getFrameBufferFrom (const Image& image)
  162. {
  163. if (OpenGLFrameBufferImage* const glImage = dynamic_cast<OpenGLFrameBufferImage*> (image.getPixelData()))
  164. return &(glImage->frameBuffer);
  165. return nullptr;
  166. }
  167. } // namespace juce