mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-20 01:14:20 +00:00
Added some OpenGL framebuffer functionality.
This commit is contained in:
parent
d3935a9b91
commit
4afcdaaaba
3 changed files with 148 additions and 57 deletions
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue