QGLwidget pops out from qmainwindow even if it's the mainwindow.ui - c++

i have a MainWindow which displays some plots that come from widget promotion. Now i have decided that i want to embed a QGLWidget so that i can draw a 3D image near them.
I created a QGLWidget inside the creator design and i have promoted it to MyGLWidget class
MyGLWidget.h
#ifndef MYGLWIDGET
#define MYGLWIDGET
#include <QtOpenGL>
#include <QGLWidget>
#include <array>
class MyGLWidget : public QGLWidget{
Q_OBJECT // must include this if you use Qt signals/slots
public:
explicit MyGLWidget(QWidget *parent = 0);
std::array<GLfloat, 3> angles;
protected:
// Set up the rendering context, define display lists etc.:
void initializeGL();
// draw the scene:
void paintGL();
// setup viewport, projection etc.:
void resizeGL (int width, int height);
};
#endif // MYGLWIDGET
MyGLWidget.cpp
#include "myglwidget.h"
#include <gl/GLU.h>
#include <iostream>
MyGLWidget::MyGLWidget(QWidget *parent){
angles[0] = 50.0;
angles[1] = 15.0;
}
/*
* Sets up the OpenGL rendering context, defines display lists, etc.
* Gets called once before the first time resizeGL() or paintGL() is called.
*/
void MyGLWidget::initializeGL(){
//activate the depth buffer
glEnable(GL_DEPTH_TEST);
}
/*
* Sets up the OpenGL viewport, projection, etc. Gets called whenever the widget has been resized
* (and also when it is shown for the first time because all newly created widgets get a resize event automatically).
*/
void MyGLWidget::resizeGL (int width, int height){
glViewport( 0, 0, (GLint)width, (GLint)height );
/* create viewing cone with near and far clipping planes */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 30.0);
glMatrixMode( GL_MODELVIEW );
}
/*
* Renders the OpenGL scene. Gets called whenever the widget needs to be updated.
*/
void MyGLWidget::paintGL(){
//delete color and depth buffer
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-20.0f); //move along z-axis
glRotatef(angles[0],0.0,1.0,0.0); //rotate 30 degress around y-axis
glRotatef(angles[1],1.0,0.0,0.0); //rotate 15 degress around x-axis
/* create 3D-Cube */
glBegin(GL_QUADS);
//front
glColor3f(1.0,0.0,0.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
//back
glColor3f(0.0,1.0,0.0);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(1.0,-1.0,-1.0);
//top
glColor3f(0.0,0.0,1.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(1.0,1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);
//bottom
glColor3f(0.0,1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0,1.0);
//right
glColor3f(1.0,0.0,1.0);
glVertex3f(1.0,1.0,1.0);
glVertex3f(1.0,-1.0,1.0);
glVertex3f(1.0,-1.0,-1.0);
glVertex3f(1.0,1.0,-1.0);
//left
glColor3f(1.0,1.0,0.0);
glVertex3f(-1.0,1.0,1.0);
glVertex3f(-1.0,-1.0,1.0);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,1.0,-1.0);
glEnd();
}
Now in the constructor of mainwindow.cpp i call ui->wgl->show(); where wgl is the ObjectName of the widget promoted to my class.
The cube is rendered but the widget pops out from the mainwindow instead of stay where i designed it

Your widget has no parent, but in Qt widget without parent is a separate window, so try to do this in constructor.
MyGLWidget::MyGLWidget(QWidget *parent) : QGLWidget(parent)
{
angles[0] = 50.0;
angles[1] = 15.0;
}
If you really use Qt Designer, then you have ui->setupUi(this); in your code. It does something like this (allocate memory and set parent):
MyGLWidget *wgl = new MyGLWidget(this);
It passes this as parent, but your current MyGLWidget take it but ignores it. So with code in my answer all should be fine.

Related

QOpenGLWidget resize results in incorrect viewport size

I have some issues with my QOpenGLWidget resizing functionality. Obviously, I am aiming for a new viewport with the correct amount of pixels and a scene centered in the actual center of my window. But these two things are off somehow.
Here are some images:
Initial one:
Scaled in Y:
Scaled in X:
The result is pixelated and translated. For me it looks like the GL viewport has the correct amount of pixels, but is scaled to the top and to the right (if the (0,0) is defined as the bottom left corner).
Here is my code:
void GLWidget::initializeGL() {
QOpenGLFunctions::initializeOpenGLFunctions();
glClearColor(0.7f, 0.75f, 0.8f, 1.0f);
glEnable(GL_MULTISAMPLE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void GLWidget::resizeGL(int w, int h) {
qreal aspect = qreal(w) / qreal(h ? h : 1);
const qreal zNear = 3, zFar = 7, fov = 3.14/6;
//I will leave this at it is. This cannot cause the viewport translation
mGraphics->setProjectionPers(fov, aspect, zNear, zFar);
}
void GLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
//actual Drawing
//...
}
The resizeGL is called with the correct values. What am I doing wrong for having a pixelated and translated image when I run this piece of code?
For whatever reason this was in the header file of my QOpenGLWidget decendant:
void resizeEvent(QResizeEvent* ev) {
resizeGL(width(), height());
}
This pretty much skips all the resize logic of the QOpenGLWidget class.

Qt - update PaintGL

I have done some research trough the different threads about PaintGL on SO, but I couldn't manage to find what I need to make it work / understand completely.
I am trying to draw a cube. EVerytime my pushbutton gets clicked the cube should rotate. (only when it gets clicked, no timers etc)
To determine the angle I use the variable xAngle. I am able to modify it trough the function setAngleCube(), but my cube doesn't seem to move. (I see the var 'i' being changed every time.)
why? How could I make it work?
To me it looks like the cube just keeps its value from the constructor and doesn't modiy them any more.
solution:
add this line in the slot of the pushbutton
ui->widget->setCubeAngle(ui->widget->getCubeAngle()+5);
credit to #Alexander Chernin
my code:
MyGLWidget::MyGLWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
xRot = 0;
yRot = 0;
zRot = 0;
xAngle=15;
qDebug("constructor\n") ;
}
void MyGLWidget::setCubeAngle(int angle)
{
xAngle = angle;
qDebug("angle set\n");
}
int MyGLWidget::getCubeAngle()
{
return xAngle;
}
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
Glptr = new MyGLWidget();
}
void Widget::on_pushButton_clicked()
{
static int i;
i+=5;
Glptr->setCubeAngle(i);
update();
qDebug()<<i<<endl;
ui->widget->setCubeAngle(ui->widget->getCubeAngle()+5); //SOLUTION
}
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
qDebug("painting cube\n");
qDebug()<
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(getCubeAngle(),0.0,1.0,0.0); //rotate 30 degress around y-axis
glRotatef(5.0,1,0.0,0.0); //rotate 15 degress around x-axis
glBegin(GL_QUADS);
//back
glColor3f(1,0,0);
glVertex3f(-0.5, 0.2,-0.5 );
glVertex3f(-0.7, 0.2,-0.5);
glVertex3f(-0.7, -0.2,-0.5 );
glVertex3f(-0.5, -0.2,-0.5);
//some similar code to draw other sides of the cube
}
try to call updateGL() in MyGLWidget::setCubeAngle:
void MyGLWidget::setCubeAngle(int angle)
{
xAngle = angle;
qDebug("angle set\n");
updateGL();
}

OpenGL sine wave amplitude and frequency change

I wrote an OpenGL program to draw a sine wave:
#include <QtGui/QtGui>
#include <QtOpenGL/QtOpenGL>
#include <math.h>
#include "globj2.h"
#include <iostream>
using namespace std;
GLobj2::GLobj2(QWidget *parent)
: QGLWidget(parent)
{
}
GLobj2::~GLobj2()
{
}
//Initialize the GL settings
void GLobj2::initializeGL()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glPointSize(2.0);
glLineWidth(1.0);
}
//Set up the viewport based on the screen dimentions
//Function is called implicitly by initializeGL and when screen is resized
void GLobj2::resizeGL( int w, int h )
{
//algorithm to keep scene "square" (preserve aspect ratio)
//even if screen is streached
if(w>h)
glViewport((w-h)/2, 0, h, h);
else
glViewport(0, (h-w)/2, w, w);
//setup the projection and switch to model view for transformations
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1, 1, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//implicit call to paintGL after resized
}
//Paints the GL scene
void GLobj2::paintGL()
{
glClear (GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glBegin(GL_LINE_STRIP);
double amp=1;
double freq = 4;
double t=0.0;
for (double x=-1.0; x<=1; x+=0.001)
{
double y = amp * cos(2 * 3.14 * freq * x );
glVertex2f(x, y);
t+=10.0;
}
glEnd();
glFlush ();
}
I have frequency and volume sliders defined as below:
QSlider *volume = new QSlider(Qt::Horizontal);
QLCDNumber *lcd1 = new QLCDNumber;
connect(volume,SIGNAL(valueChanged(int)),lcd1,SLOT(display(int)));
QLabel *label1 = new QLabel;
label1->setText("Volume:");
QDial *frequency = new QDial;
QLCDNumber *lcd2 = new QLCDNumber;
connect(frequency,SIGNAL(valueChanged(int)),lcd2,SLOT(display(int)));
QLabel *label2 = new QLabel;
label2->setText("Frequency:");
Now I want to connect frequency and volume signals from slider to sine wave freq and volume. Can you please help me figure out how to do this connection?

glutDisplayFunc displays garbage

I am trying to incorporate openGL into my c++ code for the first time. As a start up, I made this very primitive code, which defines a class called polygon and should display a polygon with a method polygon.draw(). Right now, everything below resides in a single main.cpp file, though for easy reading I am separating into section here:
The problem is, the below code compiles and runs alright. Only when the window named "simple" is created, displays garbage (mostly collected from my computer background screen :(.
Firstly, the class polygon:
#include <GL/glut.h>
#include "utility.hpp"
#include <vector>
void init(void);
class nikPolygon{
public:
std::vector<nikPosition> m_vertices;
nikColor m_color;
double m_alpha;
// constructors
// without alpha (default is 1.0)
nikPolygon(std::vector<nikPosition> vList, nikColor c):
m_vertices(vList), m_color(c), m_alpha(1.0){
}
nikPolygon(std::vector<nikPosition> vList, nikColor c, double a):
m_vertices(vList), m_color(c), m_alpha(a){
}
// default constructor
nikPolygon(){
}
// member functions
// add vertex
void addVertex(nikPosition v) { m_vertices.push_back(v); }
// remove vertex
void removeVertex(nikPosition v);
// adjust vertex
void modifyVertex(unsigned int vIndex, nikPosition newPosition);
// fill color
void setColor(nikColor col) { m_color = col; }
// set alpha
void setAlpha(double a) { m_alpha = a; }
// display
void drawPolygon(void){
// color the objet
glColor4f(m_color.red,
m_color.green,
m_color.blue,
m_alpha);
// construct polygon
glBegin(GL_POLYGON);
for (std::vector<nikPosition>::iterator it = m_vertices.begin();
it != m_vertices.end(); it++)
glVertex2f(it->x, it->y);
glEnd();
// send to screen
glFlush();
}
void draw(void);
};
Then the c/c++ callback interface (trampoline/thunk):
// for c++/c callback
nikPolygon* currentPolygon;
extern "C"
void drawCallback(void){
currentPolygon->drawPolygon();
}
void nikPolygon::draw(){
currentPolygon = this;
glutDisplayFunc(drawCallback);
}
And then the rest of it:
// initialize openGL etc
void init(void){
// set clear color to black
glClearColor(0.0, 0.0, 0.0, 0.0);
// set fill color to white
glColor3f(1.0, 1.0, 1.0);
// enable transperancy
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// setup standard orthogonal view with clipping
// box as cube of side 2 centered at origin
// this is the default view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
}
int main(int argc, char** argv){
nikPolygon poly;
poly.addVertex(nikPosition(-0.5, -0.5));
poly.addVertex(nikPosition(-0.5, 0.5));
poly.addVertex(nikPosition(0.5, 0.5));
poly.addVertex(nikPosition(0.5, -0.5));
poly.setColor(nikColor(0.3, 0.5, 0.1));
poly.setAlpha(0.4);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("simple");
init();
poly.draw();
glutMainLoop();
}
First and foremost, the original code is completely overengineered. This may be part of the original confusion. Also there's not really much you can do, to fix the code, without throwing out most of it. For example representing each polygon (triangle) with a own object instance is about as inefficient as it can get. You normally do not want to do this. The usual approach at representing a model is a Mesh, which consists of a list/array of vertex attributes, and a list of faces, which is in essence a list of 3-tuples defining the triangles, making up the surface of the mesh. In class form
class Mesh
{
std::vector<float> vert_position;
std::vector<float> vert_normal;
std::vector<float> vert_texUV;
std::vector<unsigned int> faces_indices;
public:
void draw();
};
Then to draw a mesh you use Vertex Arrays
void Mesh::draw()
{
// This is the API as used up to including OpenGL-2.1
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXCOORD_ARRAY);
// sizes of attributes depend on actual application
glVertexPointer(3, GL_FLOAT, 0, &vert_position[0]);
glNormalPointer(GL_FLOAT, 0, &vert_normal[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &vert_texUV[0]);
glDrawElements(GL_TRIANGLES, faces_indices.size(), GL_UNSIGNED_INT, &faces_indices[0]);
}
You put references to these Mesh object instances into a list, or array, and iterate over that in the display function, calling the draw method, after setting the appropriate transformation.
std::list<Mesh> list_meshes;
void display()
{
clear_framebuffer();
set_viewport_and_projection();
for(std::list<Mesh>::iterator mesh_iter = list_meshes.begin();
mesh_iter != list_meshes.end();
mesh_iter++) {
mesh_iter->draw()
}
swap_buffers();
}
At the beginning of your drawPolygon function you need to do a glClear(GL_COLOR_BUFFER_BIT);

How to flip a texture within beginNativePainting()?

I'm writing a class that inherits from QGLWidget:
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
GLWidget(QWidget *parent = 0);
~GLWidget();
void paintEvent(QPaintEvent *event);
private:
QImage* _frame;
};
The constructor of GLWidget loads an image from the disk, and paintEvent() is responsible to send the data to the GPU using native OpenGL calls that are executed between beginNativePainting() and endNativePainting(), and this works OK.
The problem is that the image is being displayed flipped (vertically), and I need to fix this. I haven't found a way to this so I'm hoping somebody can help me on this issue.
In a native Glut application I could simply call glFrustum() like this to do the flip:
static void Reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -1.0, 1.0, 1.0, -1.0, 10.0, 100.0 ); // flip vertically
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.0, 0.0, -15.0 );
}
But I've tried loading the projection matrix after the beginNativePainting() and calling glFrustum() with the same values as the call above and all I get is a black screen (which means it didn't worked as expected).
Any tips?
Also, using the mirrowed(false, true) method of QImage to do the flipping didn't had any effect in the displaying of the image.
Don't flip the projection, mirror the texture coordinates.
BTW: OpenGL assumes the origin of texture image data in the lower left corner (contrary to most windowing systems, which have it in the upper left).