Currently I am writing a video player in OpenGL.
I call gluOrtho2D like this:
gluOrtho2D(0, w, 0, h);
And output it with:
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0, this->height());
glTexCoord2f(1.0f, 0.0f); glVertex2f(this->width(), this->height());
glTexCoord2f(1.0f, 1.1f); glVertex2f(this->width(), 0);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 0.0f);
glEnd();
The correct output should be like:
But what I see is... (Please pay attention to the bottom right corner)
It seems that it's rendered incorrectly. Maybe you would recommend me to use sdl_opengl... But I'm currently using OpenGL in Qt, so I would not be able to open SDL windows.
So, what should I do?
Is it perhaps because you're using 1.1f as the y part of the 3rd texture coordinate?
Related
I want to achieve something like this .
I looked into the Qt QColormap but I did'nt get enough information to code it. If someone knows how to do this. Please share code snippet.
It's more question about color models then Qt really but basically you are trying to make a full circle around edge of HSL color model while keeping saturation.
To produce something like that in Qt you will utilize gradient brush; since we want continuous blend I used QLinearGradient. If you look at the color wheel above you will notice that red color is at 0 degrees, green is at 120 degrees and blue is at 240 degrees. QLinearGradient works with range from 0-1 so this will transform to 0, 1/3, 2/3 respectively. We also need need to add final stop which will complete the gradient back to red color.
I added bit of alpha channel to keep the color tone down so you can experiment with that; final code will look something like this:
class ColorScale : public QWidget {
Q_OBJECT
public:
using QWidget::QWidget;
protected:
void paintEvent(QPaintEvent *event) override {
QPainter painter(this);
painter.setOpacity(0.9);
painter.setRenderHint(QPainter::HighQualityAntialiasing);
QLinearGradient gradient(0, 0, 0, height());
QGradientStops stops;
stops << QGradientStop(0, Qt::red);
stops << QGradientStop(1.0/3, Qt::blue);
stops << QGradientStop(2.0/3, Qt::green);
stops << QGradientStop(1, Qt::red);
gradient.setStops(stops);
painter.fillRect(rect(), gradient);
}
};
And it produces this:
You can add labels by calling QPainter::drawText.
I'm trying to show a rounded avatar QPixMap with a white border around it. However, I have no clue as to how I could add the border... Is it even possible?
This is the function I have to draw the avatar image.
void AccountDropDownMenu::setAvatar(
const QByteArray& bytes)
{
QPixmap new_avatar;
new_avatar.loadFromData(bytes);
new_avatar = new_avatar.scaledToHeight(40, Qt::SmoothTransformation);
QBitmap map(new_avatar.size());
map.fill(Qt::color0);
QPainter painter(&map);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
painter.setPen(QPen(Qt::white, 10));
painter.drawRoundedRect(
m_avatar_label->x(),
m_avatar_label->y(),
new_avatar.width(),
new_avatar.height(),
45,
45);
new_avatar.setMask(map);
avatar_label->setPixmap(new_avatar);
}
Update
Thanks to dtech I was able to get the desired output using the following updated function.... Although it's a bit pixly (the border).
void AccountDropDownMenu::setAvatar(
const QByteArray& bytes)
{
QPixmap new_avatar;
new_avatar.loadFromData(bytes);
new_avatar = new_avatar.scaledToHeight(40, Qt::SmoothTransformation);
QBitmap map(new_avatar.size());
map.fill(Qt::color0);
QPainter painter(&map);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
painter.drawRoundedRect(
QRectF(
avatar_label->x(),
avatar_label->y(),
new_avatar.width(),
new_avatar.height()),
40,
40);
new_avatar.setMask(map);
QPainter painter2(&new_avatar);
painter2.setRenderHint(QPainter::Antialiasing);
painter2.setPen(QPen(Qt::white, 1));
painter2.drawRoundedRect(
QRectF(
avatar_label->x(),
avatar_label->y(),
new_avatar.width(),
new_avatar.height()),
40,
40);
avatar_label->setPixmap(new_avatar);
}
In Qt you draw fills with a brush, but outlines are drawn with a QPen.
I haven't used QPainter in a long time, but IIRC, the default pen is zero width, which would explain why you aren't getting anything - you are not setting a pen.
Also, you don't need "another" rounded rectangle, you can apply fill and outline to the same geometry, as demonstrated in this answer.
Update:
Your updated code sets a mask, which sets an alpha channel. That cuts away from what you already have, it could not possibly add anything. You have to paint on the pixmap. Simply use new_avatar as the paint device - QPainter painter(&new_avatar); and get rid of the rest.
I have a program which functions similar to paint, and I have a change request as such:
Add a new function named mirror mode, in a mirror mode, the canvas is divided by left and right half. All the pictures that are drawn in one of the half should be mirrored to the opposite half.
I have added code such that the mirrored portion appears; however the original image does not appear to be drawn by QPainter. Is there a simple thing I'm missing to get QPainter to show both the mirrored image and drawn image. The relevant source code is as follows :
//
void ImageArea::paintEvent(QPaintEvent *event)
{
QPainter *painter = new QPainter();
painter->begin(this);
QRect *rect = new QRect(event->rect());
painter->setBrush(QBrush(QPixmap(":media/textures/transparent.jpg")));
painter->drawRect(0, 0,
mImage->rect().right() - 1,
mImage->rect().bottom() - 1);
painter->drawImage(event->rect(), *mImage, event->rect());
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(Qt::black));
painter->drawRect(QRect(mImage->rect().right(),
mImage->rect().bottom(), 6, 6));
painter->drawImage(event->rect(), *mImage, event->rect());
painter->end();
painter->begin(this);
QImage tmp(mImage->mirrored(true,false));
painter->drawImage(0, 0, tmp);
painter->end();
}
Whatever I use for the texture coordinates, only the bottom-left pixel is ever shown (the rectangle has a solid color).
Here I set the texture coordinates:
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glTranslatef(0.5,0.0,0.0); //Have no effect
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
...
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(0, 0);
glTexCoord2f(0, 0);
glVertex2f(0, 1);
glTexCoord2f(1, 0);
glVertex2f(1, 1);
glTexCoord2f(1, 1);
glVertex2f(1, 0);
glEnd();
It is very serious. It is rendered in two different QGLWidgets. In one Widget the texture looks fine and in the other I get only the bottom left pixel.
I found the mistake. I think that anywhere between the two render processes of the two widgets , is the flag GL_TEXTURE_RECTANGLE_NV setted. I thought that glEnable(GL_TEXTURE_2D); disabled automatically the GL_TEXTURE_RECTANGLE_NV flag. But it seems not.
So the following solved my Problem:
glDisable(GL_TEXTURE_RECTANGLE_NV);
I write an OpenGL based vector graphics renderer for my application. It needs to render to a framebuffer object rather to the screen directly. Since I write the application in Qt, I use a QGLFramebufferObject which is a wrapper class for a OpenGL framebuffer object.
I created a minimal example which shows a wrong result I also get when rendering more complex stuff (for example using a fragment shader which sets colors with a non-one alpha value). I just render a red circle and a half-transparent green one on a black cleared screen, and then the same on the FBO:
void MainWidget::initializeGL()
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0, 0, 0, 0);
}
void MainWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
void MainWidget::paintGL()
{
// DRAW ON THE SCREEN
{
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(100);
glEnable(GL_POINT_SMOOTH);
glBegin(GL_POINTS);
glColor4f(1, 0, 0, 1);
glVertex2f(-.2, 0);
glColor4f(0, 1, 0, .5);
glVertex2f( .2, 0);
glEnd();
}
QGLFramebufferObject fbo(width(), height());
fbo.bind();
// DRAW ON THE FBO USING THE SAME CODE AND THE SAME CONTEXT
{
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(100);
glEnable(GL_POINT_SMOOTH);
glBegin(GL_POINTS);
glColor4f(1, 0, 0, 1);
glVertex2f(-.2, 0);
glColor4f(0, 1, 0, .5);
glVertex2f( .2, 0);
glEnd();
}
fbo.release();
fbo.toImage().save("debug.png");
}
The result looks like this on the screen (scaled 400%):
The rendering to the QGLFramebufferObject looks like this (also scaled 400%):
Note that this image is not fully opaque, so here it is the same image with a checkerboard added behind it:
Even the area in which the two circles overlap isn't fully opaque. And the anti-aliasing looks pretty ugly.
How does this happen? And how can I fix this?
I already tried:
Different blend functions.
Explicitly disabling the depth buffer, stencil buffer and sampling on the QGLFramebufferObject. I'm not sure if the QGLFramebufferObject default format adds something I don't want.
Try the following:
QGLFramebufferObjectFormat fmt;
fmt.setSamples(1); // or 4 or disable this line
fmt.setInternalTextureFormat(GL_RGBA8);
QGLFramebufferObject fbo(width(), height(), fmt);
This forces a specific pixel format and also disables rendering to a texture by using multisampling (otherwise QT always renders to a texture). That might produce different results. You can also experiment with the format.
Also, what is your hardware? My maximal point size is only 64 pixels (GTX 260), you are trying to render 100 pixel points. That might be an issue. Are any OpenGL errors generated? Does the same happen on small points?
You might also try hinting (if it's possible in QT):
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
But i wouldn't expect this to change anything.