Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/Qt6 - Fix dropperSampler not working correctly #700

Open
wants to merge 6 commits into
base: feature/qt6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 85 additions & 4 deletions src/lib/app/RvCommon/GLView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,92 @@ namespace Rv
#endif
}

bool GLView::validateReadPixels(int x, int y, int w, int h)
{
int r = x + w;
int t = y + h;

// are the extents of the read region out of bounds?
if (x < 0 || y < 0 || r > width() || t > height())
return false;

return true;
}

QImage GLView::readPixels(int x, int y, int w, int h)
{

// If out of bounds, return an empty image.
if (validateReadPixels(x, y, w, h) == false)
{
QImage image(0, 0, QImage::Format_RGBA8888);
return image;
}

//
// Why this method exists, and why saving and restoring the context is
// important:
//
// With the old QGLWidget implement with Qt 5.15.2, the current context
// stayed bounded to the main view (eg: the instance of GLView) after
// each paint of the GLView. This made it possible This made it possible
// to call gl functions (eg: glReadPixels) even when not in the context
// of a render call For example, in Mu:
//
// method: render (void; Event event)
//
// Now with the new QOpenGL paradigm, after the application is done
// rendering, the current OpenGL context is no longer bound to the
// context of the GLView, and is instead bound to the context of the
// main Qt frame window.
//
// This caused a problem with some tools, like the dropperSample() tool
// of the mu annotation toolset, which blindly called glReadPixels
// whenever the mouse was clicked/dragged over the view. Since the
// context was no longer bound to the view, but to the qapplication's
// main window, glReadPixels would return invalid colors.
//
// Therefore we implemented this readPixels on the glView, and exposed a
// "framebufferPixelValue(x,y)" method which ends up here, allowing us
// to perform some save/retore operations of the context before
// returning.
//
// Note that we can't simply make the GLiew's context current without
// restoring the old context, since this creates side effects and causes
// the glDebug() to complain about invalid states elsewhere.
//

// Save the current context
QOpenGLContext* prevContext = QOpenGLContext::currentContext();
QSurface* prevSurface = prevContext->surface();

// Make the current context the one of the GL view
makeCurrent();

QImage image(w, h, QImage::Format_RGBA8888);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());

// Restore the old context
prevContext->makeCurrent(prevSurface);

return image;
}

void GLView::debugSaveFramebuffer()
{
// Create a QImage with the same size as the FBO
QImage image(width(), height(), QImage::Format_RGBA8888);
glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE,
image.bits());

// image.save("/home/<username>>/<orv_folder>/fbo.png");
}

void GLView::swapBuffersNoSync()
{
glFlush();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER,
context()->defaultFramebufferObject());
glReadBuffer(GL_BACK);
glDrawBuffer(GL_FRONT);
glBlitFramebufferEXT(0, 0, width(), height(), 0, 0, width(), height(),
Expand Down Expand Up @@ -423,9 +505,8 @@ namespace Rv
// Not sure why it is not complaining on Linux or Windows, but this
// make sure that we are drawing onto the default framebuffer with
// those OpenGL functions below.
glBindFramebuffer(
GL_FRAMEBUFFER,
QOpenGLContext::currentContext()->defaultFramebufferObject());
glBindFramebuffer(GL_FRAMEBUFFER,
context()->defaultFramebufferObject());

glPushAttrib(GL_COLOR_BUFFER_BIT);
TWK_GLDEBUG;
Expand Down
46 changes: 46 additions & 0 deletions src/lib/app/RvCommon/MuUICommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ namespace Rv
context->listType(context->tupleType(types));

commands->addSymbols(
new Function(c, "framebufferPixelValue", framebufferPixelValue,
None, Return, "vector float[4]", Parameters,
new Param(c, "px", "float"),
new Param(c, "py", "float"), End),

new Function(c, "resizeFit", resizeFit, None, Return, "void", End),

new Function(c, "setViewSize", setViewSize, None, Return, "void",
Expand Down Expand Up @@ -507,6 +512,47 @@ namespace Rv
EndArguments);
}

NODE_IMPLEMENTATION(framebufferPixelValue, Mu::Vector4f)
{
Process* p = NODE_THREAD.process();
MuLangContext* c = static_cast<MuLangContext*>(p->context());
Session* s = Session::currentSession();
RvDocument* doc = reinterpret_cast<RvDocument*>(s->opaquePointer());
QWidget* w = doc->view();

GLView* glview = dynamic_cast<GLView*>(w);

Mu::Vector4f v;
v[0] = 0;
v[1] = 0;
v[2] = 0;
v[3] = 0;

if (glview != NULL)
{
float x = NODE_ARG(0, float);
float y = NODE_ARG(1, float);

int ix = (int)(x + 0.5f);
int iy = (int)(y + 0.5f);

QImage image = glview->readPixels(ix, iy, 1, 1);

if ((image.width() > 0) && (image.height() > 0))
{
QRgb rgba = image.pixel(0, 0);
QColor qc(rgba);

v[0] = qc.redF();
v[1] = qc.greenF();
v[2] = qc.blueF();
v[3] = qc.alphaF();
}
}

NODE_RETURN(v);
}

NODE_IMPLEMENTATION(queryDriverAttribute, Pointer)
{
Process* p = NODE_THREAD.process();
Expand Down
4 changes: 4 additions & 0 deletions src/lib/app/RvCommon/RvCommon/GLView.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ namespace Rv

void* syncClosure() const { return m_syncThreadData; }

QImage readPixels(int x, int y, int w, int h);

public slots:
void eventProcessingTimeout();

Expand All @@ -72,6 +74,8 @@ namespace Rv
void resizeGL(int w, int h);
void paintGL();
void swapBuffersNoSync();
bool validateReadPixels(int x, int y, int w, int h);
void debugSaveFramebuffer();

private:
RvDocument* m_doc;
Expand Down
1 change: 1 addition & 0 deletions src/lib/app/RvCommon/RvCommon/MuUICommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace Rv
NODE_DECLARATION(launchTLI, void);
NODE_DECLARATION(rvioSetup, void);
NODE_DECLARATION(javascriptMuExport, void);
NODE_DECLARATION(framebufferPixelValue, Mu::Vector4f);

} // namespace Rv

Expand Down
1 change: 1 addition & 0 deletions src/lib/ip/IPCore/ImageRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,7 @@ namespace IPCore
// is this needed ? YES this is needed, otherwise fonts wont render
// right with FTGL
GLPushAttrib attr1(GL_ALL_ATTRIB_BITS);
TWK_GLDEBUG;
GLPushClientAttrib attr2(GL_CLIENT_ALL_ATTRIB_BITS);
TWK_GLDEBUG;

Expand Down
3 changes: 1 addition & 2 deletions src/plugins/rv-packages/annotate/annotate_mode.mu
Original file line number Diff line number Diff line change
Expand Up @@ -672,8 +672,7 @@ class: AnnotateMinorMode : MinorMode
sName = sourceNameWithoutFrame(pinfo.name),
ip = state.pointerPosition;

float[] pixels;
glReadPixels(ip.x, ip.y, 1, 1, GL_RGBA, pixels);
let pixels = framebufferPixelValue(ip.x, ip.y);
let c = Color(pixels[0], pixels[1], pixels[2], pixels[3]);
_sampleColor += c;
_sampleCount++;
Expand Down
Loading