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.

208 lines
6.9KB

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