Browse Source

Added some OpenGL framebuffer functionality.

tags/2021-05-28
jules 13 years ago
parent
commit
4afcdaaaba
3 changed files with 148 additions and 57 deletions
  1. +121
    -5
      modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp
  2. +25
    -1
      modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.h
  3. +2
    -51
      modules/juce_opengl/opengl/juce_OpenGLImage.cpp

+ 121
- 5
modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp View File

@@ -250,6 +250,34 @@ private:
JUCE_DECLARE_NON_COPYABLE (Pimpl);
};
//==============================================================================
class OpenGLFrameBuffer::SavedState
{
public:
SavedState (OpenGLFrameBuffer& buffer, const int w, const int h)
: width (w), height (h),
data (w * h)
{
buffer.readPixels (data, Rectangle<int> (0, 0, w, h));
}
bool restore (OpenGLFrameBuffer& buffer)
{
if (buffer.initialise (width, height))
{
buffer.writePixels (data, Rectangle<int> (0, 0, width, height));
return true;
}
return false;
}
private:
const int width, height;
HeapBlock <int32> data;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedState);
};
//==============================================================================
OpenGLFrameBuffer::OpenGLFrameBuffer() {}
@@ -257,7 +285,7 @@ OpenGLFrameBuffer::~OpenGLFrameBuffer() {}
bool OpenGLFrameBuffer::initialise (int width, int height)
{
release();
pimpl = nullptr;
pimpl = new Pimpl (width, height, true, false);
if (! pimpl->ok)
@@ -269,6 +297,28 @@ bool OpenGLFrameBuffer::initialise (int width, int height)
void OpenGLFrameBuffer::release()
{
pimpl = nullptr;
savedState = nullptr;
}
void OpenGLFrameBuffer::saveAndRelease()
{
if (pimpl != nullptr)
{
savedState = new SavedState (*this, pimpl->width, pimpl->height);
pimpl = nullptr;
}
}
bool OpenGLFrameBuffer::reloadSavedCopy()
{
if (savedState != nullptr
&& savedState->restore (*this))
{
savedState = nullptr;
return true;
}
return false;
}
int OpenGLFrameBuffer::getWidth() const noexcept { return pimpl != nullptr ? pimpl->width : 0; }
@@ -277,6 +327,10 @@ GLuint OpenGLFrameBuffer::getTextureID() const noexcept { return pimpl != nu
bool OpenGLFrameBuffer::makeCurrentTarget()
{
// trying to use a framebuffer after saving it with saveAndRelease()! Be sure to call
// reloadSavedCopy() to put it back into GPU memory before using it..
jassert (savedState == nullptr);
return pimpl != nullptr && pimpl->bind();
}
@@ -295,6 +349,70 @@ void OpenGLFrameBuffer::clear (const Colour& colour)
}
}
bool OpenGLFrameBuffer::readPixels (void* target, const Rectangle<int>& area)
{
if (! makeCurrentTarget())
return false;
OpenGLHelpers::prepareFor2D (pimpl->width, pimpl->height);
glPixelStorei (GL_PACK_ALIGNMENT, 4);
glReadPixels (area.getX(), area.getY(), area.getWidth(), area.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, target);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
return true;
}
bool OpenGLFrameBuffer::writePixels (const void* data, const Rectangle<int>& area)
{
if (! makeCurrentTarget())
return false;
OpenGLHelpers::prepareFor2D (pimpl->width, pimpl->height);
glDisable (GL_DEPTH_TEST);
glDisable (GL_BLEND);
#if JUCE_OPENGL_ES
// GLES has no glDrawPixels function, so we have to create a texture and draw it..
GLuint temporaryTexture = 0;
glGenTextures (1, &temporaryTexture);
jassert (temporaryTexture != 0); // can't create a texture!
if (temporaryTexture != 0)
{
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, temporaryTexture);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, area.getWidth(), area.getHeight(), 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const int cropRect[4] = { 0, 0, area.getWidth(), area.getHeight() };
glTexParameteriv (GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
glDrawTexiOES (area.getX(), area.getY(), 1, area.getWidth(), area.getHeight());
glBindTexture (GL_TEXTURE_2D, 0);
glDeleteTextures (1, &temporaryTexture);
}
#else
glRasterPos2i (area.getX(), area.getY());
glBindTexture (GL_TEXTURE_2D, 0);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glDrawPixels (area.getWidth(), area.getHeight(), GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
#endif
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
return true;
}
void OpenGLFrameBuffer::draw2D (float x1, float y1,
float x2, float y2,
float x3, float y3,
@@ -332,9 +450,7 @@ public:
: firstSlice (nullptr),
windingMask (p.isUsingNonZeroWinding() ? -1 : 1)
{
PathFlatteningIterator iter (p);
while (iter.next())
for (PathFlatteningIterator iter (p); iter.next();)
addLine (floatToInt (iter.x1), floatToInt (iter.y1),
floatToInt (iter.x2), floatToInt (iter.y2));
}
@@ -575,7 +691,7 @@ private:
enum { factor = 128 };
static inline int floatToInt (const float n) noexcept { return roundToInt (n * (float) factor); }
static inline float intToFloat (const int n) noexcept { return n * (1.0f/ (float) factor); }
static inline float intToFloat (const int n) noexcept { return n * (1.0f / (float) factor); }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TrapezoidedPath);
};


+ 25
- 1
modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.h View File

@@ -49,9 +49,23 @@ public:
*/
bool initialise (int width, int height);
/** Releases the buffer, if one has been allocated. */
/** Releases the buffer, if one has been allocated.
Any saved state that was created with saveAndRelease() will also be freed by this call.
*/
void release();
/** If the framebuffer is active, this will save a stashed copy of its contents in main memory,
and will release the GL buffer.
After saving, the original state can be restored again by calling reloadSavedCopy().
*/
void saveAndRelease();
/** Restores the framebuffer content that was previously saved using saveAndRelease().
After saving to main memory, the original state can be restored by calling restoreToGPUMemory().
*/
bool reloadSavedCopy();
//==============================================================================
/** Returns true if a valid buffer has been allocated. */
bool isValid() const noexcept { return pimpl != nullptr; }
@@ -88,6 +102,12 @@ public:
float x4, float y4, float z4,
const Colour& colour) const;
/** Reads an area of pixels from the framebuffer into a specified pixel array. */
bool readPixels (void* target, const Rectangle<int>& area);
/** Writes an area of pixels into the framebuffer from a specified pixel array. */
bool writePixels (const void* target, const Rectangle<int>& area);
/** This will render an anti-aliased path into just the alpha channel of this framebuffer.
The idea here is that you can clear a framebuffer, use this to set its alpha channel, then
@@ -104,6 +124,10 @@ private:
friend class ScopedPointer<Pimpl>;
ScopedPointer<Pimpl> pimpl;
class SavedState;
friend class ScopedPointer<SavedState>;
ScopedPointer<SavedState> savedState;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLFrameBuffer);
};


+ 2
- 51
modules/juce_opengl/opengl/juce_OpenGLImage.cpp View File

@@ -74,14 +74,7 @@ namespace OpenGLImageHelpers
{
static void read (OpenGLFrameBuffer& frameBuffer, Image::BitmapData& bitmapData, int x, int y)
{
if (frameBuffer.makeCurrentTarget())
{
OpenGLHelpers::prepareFor2D (frameBuffer.getWidth(), frameBuffer.getHeight());
glPixelStorei (GL_PACK_ALIGNMENT, 4);
glReadPixels (x, y, bitmapData.width, bitmapData.height, GL_RGBA, GL_UNSIGNED_BYTE, bitmapData.data);
frameBuffer.releaseCurrentTarget();
}
frameBuffer.readPixels (bitmapData.data, Rectangle<int> (x, y, bitmapData.width, bitmapData.height));
}
};
@@ -93,49 +86,7 @@ namespace OpenGLImageHelpers
void write (const void* const data) const noexcept
{
if (frameBuffer.makeCurrentTarget())
{
OpenGLHelpers::prepareFor2D (frameBuffer.getWidth(), frameBuffer.getHeight());
glDisable (GL_DEPTH_TEST);
glDisable (GL_BLEND);
#if JUCE_OPENGL_ES
// GLES has no glDrawPixels function, so we have to create a texture and draw it..
GLuint temporaryTexture = 0;
glGenTextures (1, &temporaryTexture);
jassert (temporaryTexture != 0); // can't create a texture!
if (temporaryTexture != 0)
{
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, temporaryTexture);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, area.getWidth(), area.getHeight(), 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const int cropRect[4] = { 0, 0, area.getWidth(), area.getHeight() };
glTexParameteriv (GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
glDrawTexiOES (area.getX(), area.getY(), 1, area.getWidth(), area.getHeight());
glBindTexture (GL_TEXTURE_2D, 0);
glDeleteTextures (1, &temporaryTexture);
}
#else
glRasterPos2i (area.getX(), area.getY());
glBindTexture (GL_TEXTURE_2D, 0);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glDrawPixels (area.getWidth(), area.getHeight(), GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
#endif
frameBuffer.releaseCurrentTarget();
}
frameBuffer.writePixels (data, area);
}
OpenGLFrameBuffer& frameBuffer;


Loading…
Cancel
Save