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();
}
Related
// this is the display function it is called when ever you want to draw something all drawing should be called form here
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw background
drawBackground();
glPushMatrix();
// draw hot air balloon
drawAirBalloon();
// draw spray
drawSpray();
glPopMatrix();
// draw rain
drawRain();
// draw fire
drawSpray();
calcFPS();
counter++;
glFlush();
glutSwapBuffers();
glutPostRedisplay();
}
The problem is that I can't make the fire go up with my hot air balloon. The reason why I only put the code above (display) is because I think the problem is to do with this particular code.
To see the full code, click on the link below:
hot air balloon code
This is the problem:
This is because you set the model view matrix to the identity matrix in the function circle.
Replace glLoadIdentity by glPushMatrix()/glPopMatrix() in the function circle():
void circle(double radius, double xc, double yc) {
int i;
double angle = 2 * 3.1415 / 20; // circle is drawn using 20 line.
double circle_xy[100][40];
circle_xy[0][0] = radius + xc;
circle_xy[0][1] = yc;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// set fire position
glTranslatef(-40.0, 60.0, 0.0);
glBegin(GL_POLYGON);
for (i = 1; i < 20; i++) {
circle_xy[i][0] = radius * cos(i * angle) + xc;
circle_xy[i][1] = radius * sin(i * angle) + yc;
glVertex2f(circle_xy[i - 1][0], circle_xy[i - 1][1]);
glVertex2f(circle_xy[i][0], circle_xy[i][1]);
}
glEnd();
glPopMatrix();
}
To make the code more comprehensible, I recommend to remove glTranslatef for drawAirBalloon, but to do it in display:
void drawAirBalloon(void) {
// glTranslatef(squareX, squareY, squareZ); <--- remove
// ....
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw background
drawBackground();
glPushMatrix();
glTranslatef(squareX, squareY, squareZ); // <--- insert
// draw spray
drawSpray();
// draw hot air balloon
drawAirBalloon();
glPopMatrix();
// draw rain
drawRain();
calcFPS();
counter++;
glFlush();
glutSwapBuffers();
glutPostRedisplay();
}
You do a lot of effort and you write a lot of tricky and well structured code. I relay recommend, to read about Vertex Specification and Shader. Go on, but start to get rid of the deprecated fixed function pipeline and switch to a moder way of rendering.
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.
I have an openGL widget, where I want to render a line which is dependent of mouse positions, as follows:
glPushMatrix();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1, 0, 0, 0.1);
glScalef(a, b, 0);
glBegin(GL_LINES);
glVertex2f(pushedX, pushedY);
glVertex2f(currentX, currentY);
glEnd();
glFlush();
glDisable(GL_BLEND);
glPopMatrix();
where:
pushedX=buttonPressCoordinates.x();
pushedY=buttonPressCoordinates.y();
currentX=mouseCurrentPosition.x();
currentY=mouseCurrentPosition.y();
The rendering goes good, and the line is rendered as required when I move the mouse connecting with line the pushed and current coordinates.
BUT:
the issue is, that even when I press my mouse somewhere on the widget and don't move it, it generates randomly (as I think) some (x,y) and connects the it with a line with the coordinates of mouse pressed position. Though when I start moving my mouse it starts working fine.
Please, help to fix this bug.
EDIT
The code of assigning the current values of the mouse
void MainWindow::mouseMoveEvent(QMouseEvent *eventMove)
{
if(eventMove->buttons() & Qt::LeftButton)
{
GLWidget *widget = this->findChild<GLWidget *>("glwidget");
float x = widget->getNormalizedWidth(widget->mapFromGlobal(QCursor::pos()).x());
float y = widget->getNormalizedHeight(widget->mapFromGlobal(QCursor::pos()).y());
float y_ = 1.0 - y;
mouseCurrentPosition.setX(x);
mouseCurrentPosition.setY(y_);
widget->setCurrentX(mouseCurrentPosition.x());
widget->setCurrentY(mouseCurrentPosition.y());
}
}
note: QPointF mouseCurrentPosition;, getNormalizedWidth(...) is my defined fundction which works perfect.
EDIT-2
The mouse click coordinates are updated as follows:
setMouseTracking(true);
m = true;
GLWidget *widget = this->findChild<GLWidget *>("glwidget");
float x = widget->getNormalizedWidth(widget->mapFromGlobal(QCursor::pos()).x());
float y = widget->getNormalizedHeight(widget->mapFromGlobal(QCursor::pos()).y());
float y_ = 1.0 - y;
buttonPressCoordinates.setX(x);
buttonPressCoordinates.setY(y_);
qDebug() << buttonPressCoordinates.x() << buttonPressCoordinates.y();
widget->setQ(true);
widget->setPushedX(buttonPressCoordinates.x());
widget->setPushedY(buttonPressCoordinates.y());
One thing you can try is to update currentX and currentY in the mouseMoveEvent when LeftButton is not pressed:
void MainWindow::mouseMoveEvent(QMouseEvent *eventMove)
{
GLWidget *widget = this->findChild<GLWidget *>("glwidget");
float x = widget->getNormalizedWidth(widget->mapFromGlobal(QCursor::pos()).x());
float y = widget->getNormalizedHeight(widget->mapFromGlobal(QCursor::pos()).y());
float y_ = 1.0 - y;
if(eventMove->buttons() & Qt::LeftButton)
{
buttonPressCoordinates.setX(x);
buttonPressCoordinates.setY(y_);
widget->setPushedX(buttonPressCoordinates.x());
widget->setPushedY(buttonPressCoordinates.y());
}
else
{
mouseCurrentPosition.setX(x);
mouseCurrentPosition.setY(y_);
widget->setCurrentX(mouseCurrentPosition.x());
widget->setCurrentY(mouseCurrentPosition.y());
}
}
I'm teaching myself how to use OpenGL to create graphics, and I've got a basic spiral script+rotation. The Y-Axis rotation is automatic based on a timer function, but I noticed that when I move my mouse inside the window, it seems to rotate faster than intended. Could someone please look over my script and tell me what is causing the acceleration of the timer function?
#include <Windows.h>
#include <glut.h>
#include <stdio.h>
#include <math.h>
// Change viewing volume and viewport. Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
{
GLfloat nRange = 100.0f;
//Prevent a divide by zero
if(h == 0)
h = 1;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
// Reset projection matrix stack
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Establish clipping volume (left, right, buttom, top, near, far)
if (w<= h)
glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
else
glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
//Reset Model view matrix stack
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//Define a constant for pi
#define GL_PI 3.1415f
// This function does all the initialization
void SetupRC()
{
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
// Set drawing color to green
glColor3f(0.0f, 1.0f, 0.0f);
}
// Test declaration of rotation angle
GLfloat xRot = 0;
GLfloat yRot = 0;
// Modifiable variables for the eccentricity
GLfloat xMod = 50.0f;
GLfloat yMod = 50.0f;
// Called to draw scene
void RenderScene(void)
{
GLfloat x,y,z,angle; // Storage for coordinates and angles
GLfloat sizes[2]; // Store supported point size range
GLfloat step; // Store point size increments
GLfloat curSize; //Store current point size
// Get supported point size range and step size
glGetFloatv(GL_POINT_SIZE_RANGE, sizes);
glGetFloatv(GL_POINT_SIZE_GRANULARITY, &step);
//Set the initial point size
curSize = sizes[0];
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT);
// Save matrix state and do the rotation
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// specify point size before primitive is specified
glPointSize(curSize);
//Call only once for remaining points
glBegin(GL_LINE_STRIP);
//Set beginning z coordinate
z = -50.0f;
//Loop around in a circle three times
for (angle = 0.0f; angle <= (2.0f*GL_PI)*3.0f; angle += 0.1f)
{
// Calculate x and y values on the circle (the major and minor axis)
x = xMod*sin(angle);
y = yMod*cos(angle);
// Specify the point and move the z value up a little
glVertex3f(x, y, z);
z += 0.5f;
}
// Done drawing points
glEnd();
// Restore transformations
glPopMatrix();
//Flush drawing commands
glFlush();
}
// Modifier Code
void CircleController (int key, int x, int y)
{
switch (key)
{
case 27 : break;
case 100 :
(yRot -= 5.0f); ; break;
case 102 :
(yRot += 5.0f); ; break;
case 101 :
(xRot -= 5.0f); ; break;
case 103 :
(xRot += 5.0f); ; break;
glutDisplayFunc(RenderScene);
}
}
void MouseHandler (int button, int state, int x, int y)
{
// Holder variable assigned to overcome printf limitation and prevent double- printing due to MouseUp function call
GLfloat Holder = xMod;
// Increases size, and decreases timer speed by increasing the amount of time needed.
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
xMod+= 5.0f;
}
// Decreases size, and increases timer speed by decreasing the amount of time needed.
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
xMod-= 5.0f ;
}
if (Holder != xMod)
printf("%d \n", Holder);
}
void TimerFunction(int value)
{
//Call the arrow key function
glutSpecialFunc(CircleController);
//Call the Mouseclick Modifier function
glutMouseFunc(MouseHandler);
if (xRot < 360)
(xRot += 1.0f);
else
(xRot = 0.0f);
// Redraw the scene with new coordinates
glutPostRedisplay();
glutTimerFunc(1.6666f, TimerFunction, 1);
}
void main(void)
{
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("Drawing Lines");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutTimerFunc(1.6666f, TimerFunction, 1);
SetupRC();
glutMainLoop();
}
Eric Palace gave me the start
My personal theory was always that it had something to do with the window focus and which program is given more CPU time, but that's just pure speculation.
That makes sense to me. But wait, don't you only paint on a timer? Wouldn't that prevent additional CPU time from modifying movement speed? Yes you do. Sortof.
glutTimerFunc(1.6666f, TimerFunction, 1);
The doc's for glutTimerFunc say that the first parameter is an unsigned int, representing the timer in milliseconds. So you're telling glut "call this function every 1 millsecond." (Approx 1000FPS) And since it takes longer than one millisecond to execute, you're effectively telling it "run this function over and over as fast as you possibly can". Which it does. And so additional CPU time is making a difference.
To avoid situtations like this (aside from correcting the 1.6666f parameter), it's usually suggested to
update the "world" in separate functions from painting the screen. In fact, I would imagine it to be common to have two or more world update functions. One for stuff that needs updating with the paint: arrows and running characters, one for stuff that only changes once a second or so: mana regen and npc decisions, and one for really slow stuff: respawns.
During an "update", check how much time has passed since the last update, (maxing out at half a second or so), and make the world update that much. Then if updates run twice as often or half as often for any reason, the game doesn't appear to speed up or slow down, you just just more/fewer frames instead.
Here's what such an update might look like
radians xrot = 0; //use a units class
radians rot_per_second = .01;
void updateFrame(double time_passed) {
assert(time_passed>=0 && time_passed <= 1.0);
radians rotate_thistime = rot_per_second * time_passed;
xrot += rotate_thistime;
}
void do_updates() {
static clock_t lastupdatetime = clock()-1; //use openGL functions instead of C
clock_t thisupdatetime = clock();
double seconds = double(thisupdatetime-lastupdatetime)/CLOCKS_PER_SEC;
if (seconds > 0.5) //if something happened and haven't update in a long time
seconds = 0.5; //pretend only half a second passed.
//this can happen if
// computer is overloaded
// computer hibernates
// the process is debugged
// the clock changes
if (seconds <= 0.0) //computer is REALLY fast or clock changed
return; //skip this update, we'll do it when we have sane numbers
updateFrame(seconds);
lastupdatetime = thisupdatetime;
}
Alright, I'm trying to recreate the old classic, Missile Command, using OpenGL in C++. This is my first foray into OpenGL, although I feel fairly comfortable with C++ at this point.
I figured my first task was to figure out how to move 2d objects around the screen, seemed like it would be fairly simple. I created two quick method calls to make either triangles or quads:
void makeTriangle(color3f theColor, vertex2f &p1, vertex2f &p2, vertex2f &p3,
int &xOffset, int &yOffset)
{
//a triangle
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glEnd();
}
void makeQuad(color3f theColor, vertex2f &p1, vertex2f &p2, vertex2f &p3,
vertex2f &p4, int &xOffset, int &yOffset)
{
//a rectangle
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glVertex2f(p4.x, p4.y);
glEnd();
}
color3f and vertex2f are simple classes:
class vertex2f
{
public:
float x, y;
vertex2f(float a, float b){x=a; y=b;}
};
class color3f
{
public:
float red, green, blue;
color3f(float a, float b, float c){red=a; green=b; blue=c;}
};
And here is my main file:
#include <iostream>
#include "Shapes.hpp"
using namespace std;
int xOffset = 0, yOffset = 0;
bool done = false;
void keyboard(unsigned char key, int x, int y)
{
if( key == 'q' || key == 'Q')
{
exit(0);
done = true;
}
if( key == 'a' )
xOffset = -10;
if( key == 'd' )
xOffset = 10;
if( key == 's' )
yOffset = -10;
if( key == 'w' )
yOffset = 10;
}
void init(void)
{
//Set color of display window to white
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//Set parameters for world-coordiante clipping window
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-400.0,400.0,-300.0,300.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
color3f aGreen(0.0, 1.0, 0.0);
vertex2f pa(-400,-200);
vertex2f pb(-400,-300);
vertex2f pc(400,-300);
vertex2f pd(400,-200);
makeQuad(aGreen,pa,pb,pc,pd,xOffset,yOffset);
color3f aRed(1.0, 0.0, 0.0);
vertex2f p1(-50.0,-25.0);
vertex2f p2(50.0,-25.0);
vertex2f p3(0.0,50.0);
makeTriangle(aRed,p1,p2,p3,xOffset,yOffset);
glFlush();
}
int main(int argc, char** argv)
{
// Create Window.
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow("test");
// Some initialization.
init();
while(!done)
{
//display functions
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
// Start event loop.
glutMainLoop();
}
return 0;
}
A quad is defined as the "background" for the time being and consists of just a green rectangle along the bottom of the screen. The red triangle is the "object" that I wish to move. On a keypress, an offset is saved in the direction indicated.
I've tried using glTranslatef(xOffset,yOffset,0); but the problem with that is that it moves both elements on the screen and not just the red triangle. I attempted to put the whole call to draw the triangle between a push and pop matrix operation:
PushMatrix();
glTranslatef(xOffset,yOffset,0);
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glEnd();
PopMatrix();
As far as I can tell, that destroys any changes that the translation was doing beforehand.
I've also tried just changing the values of the x and y coordinates before calling the draw, but that just causes a brief flicker before leaving the triangle in its original position:
p1.x += xOffset;
p2.x += xOffset;
p3.x += xOffset;
p1.y += yOffset;
p2.y += yOffset;
p3.y += yOffset;
There has to be a nice simple way of doing this, and I'm just overlooking it. Could someone offer a suggestion please?
EDIT:
My actual problem was that I was never refreshing the screen after an initial draw. What I needed was to specify an idle function inside my main loop:
glutIdleFunc(IdleFunc);
Where the actual IdleFunc looks like:
GLvoid IdleFunc(GLvoid)
{
glutPostRedisplay();
}
Instead of using glFlush() inside my draw function, I should have been using glutSwapBuffers(). By doing that, the code I had first come up with:
p1.x += xOffset;
p2.x += xOffset;
p3.x += xOffset;
p1.y += yOffset;
p2.y += yOffset;
p3.y += yOffset;
Works fine for my purposes. I didn't have a need to translate the matrix, I just needed to draw the element in a different position from one scene to the next.
GL_MODELVIEW is what you need.
From the OpenGL FAQ, 2.1: http://www.opengl.org/resources/faq/technical/gettingstarted.htm
program_entrypoint
{
// Determine which depth or pixel format should be used.
// Create a window with the desired format.
// Create a rendering context and make it current with the window.
// Set up initial OpenGL state.
// Set up callback routines for window resize and window refresh.
}
handle_resize
{
glViewport(...);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set projection transform with glOrtho, glFrustum, gluOrtho2D, gluPerspective, etc.
}
handle_refresh
{
glClear(...);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set view transform with gluLookAt or equivalent
// For each object (i) in the scene that needs to be rendered:
// Push relevant stacks, e.g., glPushMatrix, glPushAttrib.
// Set OpenGL state specific to object (i).
// Set model transform for object (i) using glTranslatef, glScalef, glRotatef, and/or equivalent.
// Issue rendering commands for object (i).
// Pop relevant stacks, (e.g., glPopMatrix, glPopAttrib.)
// End for loop.
// Swap buffers.
}
You answer your own question, that is the solution:
glPushMatrix();
glTranslatef(xOffset,yOffset,0);
glBegin(GL_POLYGON);
glColor3f(theColor.red, theColor.green, theColor.blue);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glVertex2f(p3.x, p3.y);
glEnd();
glPopMatrix();
That will change the modelview matrix while the rectangle is drawn, then it will revert the modelview matrix back to what it were before. Did you actualy tried that? What whent wrong?
If I'm reading your code right, you want to only rotate one element right? If so, do this:
Call glPushMatrix();
then do your rotation
Store how much you've rotated
then draw your rotated item
then call glPopMatrix();
That will only rotate the one object.
EDIT:
I see that doing that "destroys" the previous rotation. Could you elaborate? That is the correct way to translate/rotate one object.
I also notice that you aren't initializing the Modelview Matrix. You should initialize the Modelview Matrix after you setup your PROJECTION matrix. You also need to make sure that you are initializing both matrices to the identity. And finally, make sure that you are initializing both matrices EVERY time the screen refreshes. To test this, set a breakpoint on your matrix initialization and see if it gets hit only once or every frame.