openGL texturing shows only red component of texture - qt

I am trying to texture map an image to a single polygon. My image is being read correctly, but only the red plane of the image is being textured.
I am doing this within a QGLWidget
I have checked the image after it is read, and it's components are being read correctly--ie, I get valid values for the green and blue planes.
Here is the code
QImageReader *theReader = new QImageReader();
theReader->setFileName(imageFileName);
QImage theImageRead = theReader->read();
if(theImageRead.isNull())
{
validTile = NOT_VALID_IMAGE_FILE;
return;
}
else
{
int newW = 1;
int newH = 1;
while(newW < theImageRead.width())
{
newW *= 2;
}
while(newH < theImageRead.height())
{
newH *= 2;
}
theImageRead = theImageRead.scaled(newW, newH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
// values checked in theImageRead are OK here
glGenTextures(1,&textureObject);
theTextureImage = QGLWidget::convertToGLFormat(theImageRead);
// values checked in theTextureImage are OK here
glBindTexture(GL_TEXTURE_2D, textureObject);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,newW, newH, 0, GL_RGBA, GL_UNSIGNED_BYTE,theTextureImage.bits() );
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFlush();
validTile = VALID_TEXTURE;
return;
}
then I draw like this:
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureTiles[tN]->getTextureObject() );
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0);
glVertex2f(textureTiles[tN]->lowerLeft.x(), textureTiles[tN]->lowerLeft.y());
glTexCoord2f(1.0,0.0);
glVertex2f(textureTiles[tN]->lowerRight.x(), textureTiles[tN]->lowerRight.y());
glTexCoord2f(1.0,1.0);
glVertex2f(textureTiles[tN]->upperRight.x(), textureTiles[tN]->upperRight.y());
glTexCoord2f(0.0,1.0);
glVertex2f(textureTiles[tN]->upperLeft.x(), textureTiles[tN]->upperLeft.y());
glEnd();
glDisable(GL_TEXTURE_2D);
}
Does anybody see anything that would cause my texture to be interpreded as if it is values of (r,0,0,1)? (r,g,b,a)?
QT 4.7.1, Ubuntu 10.04, openGl 2.something or other
thanks in advance for any help

I've had a similar problem. I found that I had to "reset" the gl color to white and opaque before drawing a texturized quad, or the colors would get messed up. Like this:
...
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureTiles[tN]->getTextureObject() );
glColor4f(1.0, 1.0, 1.0, 1.0); // reset gl color
glBegin(GL_QUADS);
...

This is a very common problem. First, set your MIN/MAG filters to something, since the defaults use mipmaps, and since you didn't provide mipmaps, the texture is incomplete.
Sampling a incomplete texture usually gives white. A glColor call with the default texture environment will multiply the vertex color with the texture color. You probably have something like glColor(red), and red * white = red, so that's why you're seeing red.
To fix it, set the MIN/MAG filters to GL_LINEAR or GL_NEAREST.

Related

How do I add a border to a rounded QPixmap?

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.

Qt drawing icons using color and alpha-map

I would like to draw icons (only one color) in different colors. To do so, I would like to import a single alpha-texture and then combine this with a given color in the application.
The result should be, that nothing is drawn on to the background, when the alpha-map has an opacity of 0 and the used color should be drawn, when the opacity is 1.
One soulution should be hidden somewhere in QPainter, since you can manually set the Composition-Mode (QPainter::setCompositionMode). But I don't get it to work like I want.
Does somebody have an idea?
Thanks in advance.
EDIT: Here is a little graphic explaining what I would like to do. I want to use a Alpha-Map like shown in the graphic and then use a color layer to create my icon. Important is, that the background stays transparent.
You can do thos using QPainter like this:
QColor color;
// set color value
// load gray-scale image (an alpha map)
QPixmap pixmap = QPixmap(":/images/earth.png");
// initialize painter to draw on a pixmap and set composition mode
QPainter painter(&pixmap);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.setBrush(color);
painter.setPen(color);
painter.drawRect(pixmap.rect());
// Here is our new colored icon!
QIcon icon = QIcon(pixmap);
Here is gray-scale image and two colored icons which i get using the code above (QPixmap.save() method):
icons
The DestinationIn composition mode will do the trick.
Draw the color layer using the default composition mode of SourceOver.
Draw the alpha layer using the DestinationIn composition mode.
For example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/alpha-mask-24943711
#include <QtWidgets>
QImage icon(int size) {
QImage image{size, size, QImage::Format_ARGB32_Premultiplied};
image.fill(Qt::transparent);
QPainter p(&image);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(Qt::NoPen);
p.translate(image.rect().center());
p.scale(image.width()/2.2, image.height()/2.2);
p.setBrush(Qt::white);
p.drawEllipse(QRectF{-.5, -.5, 1., 1.});
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.setBrush(Qt::transparent);
p.drawEllipse(QRectF{-.3, -.3, .6, .6});
for (auto angle : {0., 100., 150.}) {
p.save();
p.rotate(angle);
p.drawRect(QRectF{-.1, 0, .2, -1.});
p.restore();
}
return image;
}
QImage checkers(int size) {
QImage img{size*2, size*2, QImage::Format_ARGB32_Premultiplied};
QPainter p(&img);
p.fillRect(0, 0, size, size, Qt::darkGray);
p.fillRect(size, size, size, 2*size, Qt::darkGray);
p.fillRect(size, 0, size, size, Qt::lightGray);
p.fillRect(0, size, size, size, Qt::lightGray);
return img;
}
void drawColorIcon(QPainter & p, QColor color, const QImage & alpha)
{
p.save();
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.fillRect(QRect{0, 0, alpha.width(), alpha.height()}, color);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(0, 0, alpha);
p.restore();
}
QImage drawColorIconProof(QColor color, const QImage & alpha) {
QImage result{alpha.size(), alpha.format()};
QPainter p(&result);
drawColorIcon(p, color, alpha);
p.setCompositionMode(QPainter::CompositionMode_DestinationAtop);
p.fillRect(alpha.rect(), {checkers(10)});
return result;
}
int main(int argc, char *argv[])
{
QApplication app{argc, argv};
QLabel label;
label.setPixmap(QPixmap::fromImage(drawColorIconProof("orangered", icon(200))));
label.show();
return app.exec();
}
I found a solution. However, instead of using a transparent graphic for the alpha map like I've used in the first post, I had to use a black/white-graphic where black pixels are transparent and white pixels are not (=rendered).
// ++++ in constructor ++++
QImage alphaMap = QImage(fileName);
QColor color;
// ++++ in paint Event ++++
QPainter painter(this);
painter.setRenderHints(QPainter::RenderHint::Antialiasing);
painter.setRenderHints(QPainter::RenderHint::HighQualityAntialiasing);
// draw icon
QImage renderedIcon(alphaMap);
// fill with color
renderedIcon.fill(color);
// set alpha-map, black pixels -> opacity of 0, white pixels -> opacity 1
renderedIcon.setAlphaChannel(alphaMap);
painter.drawImage(this->rect(), renderedIcon); // draw image to QWidget
I do not quite understand the problem, but may be you can use QGraphicsColorizeEffect class? QGraphicsColorizeEffect

How do I combine a QImage and QPixmap?

I'm using PyQt, and I've loaded an image from disk into a QPixmap. I've also created a mask, using:
self.mask = QImage(self.image.width(), self.image.height(), QImage.Format_Mono)
self.mask.fill(0)
I'd like to combine the two for display, such that any pixels colored black in the mask are drawn in translucent red over the image when I render it.
I've created a custom widget, that renders the image in the paint event like so:
def paintEvent(self, event):
p = QPainter(self)
r = event.rect()
p.drawPixmap(r, self.image, r)
This works fine. What I'm less clear on is how to take the data in the mask and paint a translucent red only over those pixels in the destination image.
I've tried turning the mask into a clipping region, like this:
mask = QPixmap.fromImage(self.mask.createMaskFromColor(self.mask.color(0)))
p.setClipRegion(QRegion(mask))
color = QColor(255, 0, 0, 128)
p.setPen(Qt.NoPen)
p.setBrush(QBrush(color))
p.drawRect(r)
... but it doesn't draw anything (and draws a translucent red box over the whole image if I don't call setClipRegion).
I also tried creating the mask as a QImage.Format_ARGB4444_Premultiplied, and using transparency. And while this does work, and I can edit the mask in my program (and verify that some portions of the mask are transparent and some portions are opaque) the self.mask.createAlphaMask() method returns a solid white rectangle.
Do the "create mask" methods actually do anything?
Either change your mask's design or create a new QImage based on your mask. Then draw the QImage on the destination. It is not only a method that works, but also a method that is faster than drawing single pixels or sth. similar. I tried several ways and this was the fastest so far (on a QGLWidget).
The idea is that you encode the transparency, and also the non-marked pixels, in the QImage directly, like this:
QImage dest(<width>, <height>, QImage::Format_ARGB32);
dest.fill(qRgba(0, 0, 0, 0));
for (int y = 0; y < <height>; ++y) {
QRgb *destrow = (QRgb*)dest.scanLine(y);
for (int x = 0; x < <width>; ++x) {
if (<should be marked>)
destrow[x] = qRgba(255, 0, 0, 127);
}
}
painter.drawImage(0, 0, dest);
For reference, take a look at the code here:
https://sourceforge.net/p/gerbil/svn/60/tree/trunk/gerbil-gui/bandview.cpp#l59

Wrong alpha blending when rendering on a QGLFramebufferObject

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.

Image Rotate 3D in Flex, but display another image on back of this image?

i want to rotate 3D an Image called img1 in Flex. I want to rotate it around y axis 180 degree. I can do this by using 3D effect already built in Flex but i want to do a bit more different.
I want during rotating, there's another image called img2 appear on back of img1 (in default case, the image appear on the back is img1) and when rotating finish, the image will be img2.
How can i do this ?
Thank you.
If you need no perspective effect, it's quite easy to do. A rough implementation (not tested!):
// Event.ENTER_FRAME event listener
void on_enter_frame(event:Event):void
{
// m_angle is a member of the class/flex component where on_enter_frame is declared
// ANGLE_DELTA is just a constant
m_angle += ANGLE_DELTA;
// Angle clamping to the range [0, PI * 2)
m_angle %= Math.PI * 2;
if (m_angle < 0)
m_angle += Math.PI * 2;
// If we currently look at the front side...
if (m_angle < Math.PI)
{
img1.visible = true;
img2.visible = false;
img1.scaleX = Math.cos(m_angle);
}
else
{
img1.visible = false;
img2.visible = true;
// If you omit negation, the back-side image will be mirrored
img2.scaleX = -Math.cos(m_angle);
}
}
So every frame we increase the rotation angle, clamp it to the range [0, PI * 2). Then depending on the value of the rotation angle, we hide/show the pair of your images, and then perform x-scaling of the visible image.
Thank you, now i found a solution. Please check it here, it's very easy to do.
http://forums.adobe.com/thread/921258

Resources