I am fiddling with graphics, and trying to find a way to have the shape I am drawing (in this case, a triangle) scale with window sizing. However, I only want the width to update, and the height to remain the same.
I have done some research, and tried using glutGet(GLUT_SCREEN_WIDTH) as a multiplier or similar (e.g. (GLUT_SCREEN_WIDTH /100) - 250) to the vertices of my shape, but I feel I may be missing a key idea. Should I instead be applying the scaling operation to the viewport, not the shape's points? Whenever I scale the points, they don't seem to scale with the window. Code below.
#define GLUT_DISABLE_ATEXIT_HACK
#include <GL/glut.h>
#include <GL/gl.h>
//#include <assert.h>
void init (void)
{
glClearColor (1.0, 1.0, 0.0, 0.0); /* Set background to yellow */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex2d (0.0, 0.0);
glVertex2d(1.0, 0.0);
glVertex2d (0.5, 0.866);
glEnd();
glFlush (); //Display immediately
}
void keyEscape( unsigned char key, int x, int y )
{
switch ( key )
{
case 113: // 'Q' key for escape
int windowID = glutCreateWindow ("triangle");
glutDestroyWindow (windowID);
exit (0);
break;
}
glutPostRedisplay();
}
void mouseEscape( int button, int state, int x, int y )
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
int windowID = glutCreateWindow ("triangle");
glutDestroyWindow (windowID);
exit (0);
glutPostRedisplay();
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (250, 250);
glutInitWindowPosition ((glutGet(GLUT_SCREEN_WIDTH)-250)/2, (glutGet(GLUT_SCREEN_HEIGHT)-250)/2);
glutCreateWindow ("triangle");
init ();
glutKeyboardFunc(keyEscape);
glutMouseFunc(mouseEscape);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
Step 1: Get rid of the Init function. Projection setup is part of the drawing process.
Step 2: Use the Window width as input for the left/right parameter of glOrtho
Like this:
void display(void)
{
int const win_width = glutGet(GLUT_WINDOW_WIDTH);
int const win_height = glutGet(GLUT_WINDOW_HEIGHT);
float const win_aspect = (float)win_width / (float)win_height;
glClearColor (1.0, 1.0, 0.0, 0.0); /* Set background to yellow */
glClear (GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, win_aspect, 0.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f (0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex2d (0.0, 0.0);
glVertex2d(1.0, 0.0);
glVertex2d (0.5, 0.866);
glEnd();
glFlush (); // Tell OpenGL to process what we submitted so far
}
BTW: You should switch to a double buffered mode and use glutSwapBuffers instead of glFlush/glFinish; on some systems single buffered mode doesn't work (well). Today the only reliable method is double buffering.
Related
guys i try to make an GLUT application that could rotate object on key pressed, but it seems not worked.
#include <stdio.h>
#include <gl/glut.h>
GLfloat rotation = 90.0;
float posX = 0, posY = 0, posZ = 0;
void reshape(int width, int heigth){
/* window ro reshape when made it bigger or smaller*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//clip the windows so its shortest side is 2.0
if (width < heigth) {
glOrtho(-2.0, 2.0, -2.0 * (GLfloat)heigth / (GLfloat)width, 2.0 * (GLfloat)heigth / (GLfloat)width, 2.0, 2.0);
}
else{
glOrtho(-2.0, 2.0, -2.0 * (GLfloat)width / (GLfloat)heigth, 2.0 * (GLfloat)width / (GLfloat)heigth,2.0 , 2.0);
}
// set viewport to use the entire new window
glViewport(0, 0, width, heigth);
}
void rect(){
glBegin(GL_POLYGON);
glVertex2f(-0.2, -0.2);
glColor3f(1.0, 1.0, 0.0);
glVertex2f(-0.2, 0.2);
glColor3f(1.0, 0.0, 1.0);
glVertex2f(0.2, 0.2);
glColor3f(0.0, 1.0, 1.0);
glVertex2f(1.2, -0.2);
glColor3f(1.0, 1.0, 1.0);
glEnd();
}
void display(){
//Clear Window
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(posX,posY,posZ);
rect();
glPopMatrix();
glFlush();
}
void init(){
// 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);
//set up standard orthogonal view with clipping
//box as cube of side 2 centered at origin
//This is the default view and these statements could be removed
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
}
float move_unit = 10;
int deg = 0;
void keyboardown(int key, int x, int y)
{
switch (key){
case GLUT_KEY_RIGHT:
glRotatef((deg+=move_unit), posX, posY, posZ);;
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
glRotatef(deg-=move_unit, posX, posY, posZ);;
break;
case GLUT_KEY_UP:
glRotatef(deg-=move_unit, posX, posY, posZ);;
break;
case GLUT_KEY_DOWN:
glRotatef(deg+=move_unit, posX, posY, posZ);;
break;
default:
break;
}
glutPostRedisplay();
}
int main(int argc, char** argv){
//initialize mode and open a windows in upper left corner of screen
//Windows tittle is name of program
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Move Test");
glutDisplayFunc(display);
init();
glutSpecialFunc(keyboardown);
glutMainLoop();
}
is there is something i did it wrong?
before, i tried to use the GLUT_KEY_ for moving 2d object and it worked, but when i change the command to glrotatef, it doesn't work.
have any suggestion?
The problem here is, that you override the matrix before it is used. In keyboardown the matrix is set, but at the begin of display the glLoadIdentity(); function is called, which resets the matrix and removes the rotation.
To solve this, you can, e.g., store the rotation angle in a variable. In keyboardown you increase/decrease the angle. When rendering in the display function, you reset the matrix as already done and then add the rotation by calling glRotatef with the previously stored angle.
Here is my code that set a perspective view volume. The rectangle is displayed correctly.
I want to add a teapot to my scene now, so I add a line drawing a teapot after drawing the rectangle. But no teapot was displayed.
What params did I set wrong? What's the problem with my view and teapot?
GLint winWidth = 600, winHeight = 600; // Initial display-window size.
GLfloat x0 = 50.0, y0 = 50.0, z0 = 50.0; // Viewing-coordinate origin.
GLfloat xref = 50.0, yref = 50.0, zref = 0.0; // Look-at point.
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0; // View-up vector.
/* Set coordinate limits for the clipping window: */
//GLfloat xwMin = -40.0, ywMin = -60.0, xwMax = 40.0, ywMax = 60.0;
GLfloat xwMin = -100.0, ywMin = -100.0, xwMax = 100.0, ywMax = 100.0;
/* Set positions for near and far clipping planes: */
GLfloat dnear = 25.0, dfar = 125.0;
void init (void)
{
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
gluLookAt (x0, y0, z0, xref, yref, zref, Vx, Vy, Vz);
printf("look at orign:%.0f %.0f %.0f, pref: %.0f %.0f %.0f\n",x0, y0, z0, xref, yref, zref );
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glFrustum (xwMin, xwMax, ywMin, ywMax, dnear, dfar);
}
void displayFcn (void)
{
init ( );
glClear (GL_COLOR_BUFFER_BIT);
/* Set parameters for a square fill area. */
glColor3f (0.0, 1.0, 0.0); // Set fill color to green.
//glPolygonMode (GL_FRONT, GL_FILL);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode (GL_BACK, GL_LINE); // Wire-frame back face.
glBegin (GL_QUADS);
glVertex3f (0.0, 0.0, 0.0);
glVertex3f (100.0, 0.0, 0.0);
glVertex3f (100.0, 100.0, 0.0);
glVertex3f (0.0, 100.0, 0.0);
glEnd ( );
glutSolidTeapot(50.9);
glFlush ( );
}
void reshapeFcn (GLint newWidth, GLint newHeight)
{
glViewport (0, 0, newWidth, newHeight);
winWidth = newWidth;
winHeight = newHeight;
}
void keyboard(unsigned char key, int x, int y);
int main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (50, 50);
glutInitWindowSize (winWidth, winHeight);
glutCreateWindow ("Perspective View of A Square");
glutKeyboardFunc(keyboard);
glutDisplayFunc (displayFcn);
glutReshapeFunc (reshapeFcn);
glutMainLoop ( );
}
Your teapot is just totally off view.
You could place it inside the viewing volume like this:
glMatrixMode(GL_MODELVIEW);
glTranslatef(50.f, 50.f, 0.f);
glutSolidTeapot(50.9);
Also note that the field of view angle is insanely high for any normal viewing condition. Consider using the function gluPerspective instead of glFrustum to easily specify the angle, instead of manually having to specify the tangens of that angle scaled by the near plane distance as with glFrustum.
Also note that all of that is deprecated GL. Most of the functions you are using are removed from modern core profile contexts. If you start learning GL now, my advise is learning the new (well, 10 year old) way of using the programmable pipeline instead of the old (20 years) fixed-function pipeline with the builtin matrix stack.
I have a code:
#include <gl/glut.h>
#include <stdio.h>
#define WinW 1000
#define WinH 500
/* ----------------------------------------------------------------------- */
bool mousedown = false;
void myInit(void) {
glClearColor(1.0, 1.0, 1.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glPointSize(5.0);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, WinW, WinH, 0.0, -1.0, 1.0);
}
void myDisplay(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POINTS);
glColor3f(1.0, 0.0, 0.0);
glVertex2i(50, 50);
glEnd();
//glFlush();
glutSwapBuffers();
}
void myMouse(int button, int state, int x, int y){
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
mousedown = true;
}
else
mousedown = false;
}
void myMovedMouse(int mouseX, int mouseY){
if (mousedown){
//printf("%d %d\n", mouseX, mouseY);
glBegin(GL_POINTS);
glColor3f(0.0, 1.0, 0.0);
glVertex2i(mouseX, mouseY);
glEnd();
//glFlush();
glutSwapBuffers();
}
}
/* ----------------------------------------------------------------------- */
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(WinW, WinH);
glutInitWindowPosition(100, 150);
glutCreateWindow("Computer Graphic");
myInit();
glutDisplayFunc(myDisplay);
glutMouseFunc(myMouse);
glutMotionFunc(myMovedMouse);
glutMainLoop();
}
I want to draw free shape by mouse dragging.
I have try with glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)and glFlush(), it work for me.
But when I use GLUT_DOUBLE and glutSwapBuffers() in myMovedMouse(), the screen is blinking (black-white-black-white...)
I am new in OpenGL, anyone have solution for this.
Thanks for help!
When using double buffering, you have to draw all your points on each redraw. So you have to maintain a list of all the points. The steps are then:
On startup, create an empty point list. If you want nice code, define a class/struct that contains two values for the x and y position, and use a C++ container like std::vector for your list of points.
When you get a new point from mouse input, add that point to the point list, and call glutPostRedisplay().
In the myDisplay() function, draw all the points in the list.
Having to maintain a list of points may seem to add complexity compared to using single buffering. But as soon as you go a little farther, you will probably need it anyway. For example, if the user resizes the window, you will have to be able to redraw all the points anyway. So drawing the points one by one in single buffering mode will not get you very far.
I have this little program that is supposed to rotate a square in 2D. When I give it fixed vertexes, it works fine. But when I try to put it in motion, the square just starts to flash and blink and not really resemble a square at all. Everything looks good to me, so I must be missing something. Can anyone see it?
#include <stdio.h>
#include <math.h>
#include <glut/glut.h>
#define DEG_TO_RAD 0.017453
GLsizei ww, wh;
GLfloat theta;
void display()
{
//clear window
glClear(GL_COLOR_BUFFER_BIT);
//draw unit square polygon
glBegin(GL_POLYGON);
glVertex2f(sin(DEG_TO_RAD*theta), cos(DEG_TO_RAD*theta));
glVertex2f(-sin(DEG_TO_RAD*theta), cos(DEG_TO_RAD*theta));
glVertex2f(-sin(DEG_TO_RAD*theta), -cos(DEG_TO_RAD*theta));
glVertex2f(sin(DEG_TO_RAD*theta), -cos(DEG_TO_RAD*theta));
// glVertex2f(-0.5, -0.5);
// glVertex2f(-0.5, 0.5);
// glVertex2f(0.5, 0.5);
// glVertex2f(0.5, -0.5);
glEnd();
//flush gl buffers
glFlush();
}
void init() {
//set color to black
glClearColor(0.0, 0.0, 0.0, 0.0);
//set fill color to white
glColor3f(1.0, 1.0, 1.0);
//set up standard orthogonal view with clipping
//box as cube of side2 centered at origin
//this is default view and these statements could be removed
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
}
void myreshape(GLsizei w, GLsizei h) {
//adjust clipping window
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w<=h)
gluOrtho2D(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w);
else
gluOrtho2D(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
//adjust viewport
glViewport(0, 0, w, h);
//set global size for use by drawing routine
ww = w;
wh = h;
}
void myidle() {
theta += 2.0;
if (theta > 360.0) theta -= 360.0;
glutPostRedisplay();
}
int main(int argc, char** argv)
{
theta = 0.0;
// initialize mode and open a window in upper-left corner of screen
// window title is name of program (arg[0])
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);//Set the window size
glutInitWindowPosition(0, 0);
glutCreateWindow("rotating square");
glutDisplayFunc(display);
init();
glutReshapeFunc(myreshape);
glutIdleFunc(myidle);
glutMainLoop();
return 0;
}
Your vertex definitions just don't produce a square. Try the following:
glVertex2f(cos(DEG_TO_RAD*(theta + 135)), sin(DEG_TO_RAD*(theta + 135)));
glVertex2f(cos(DEG_TO_RAD*(theta + 45 )), sin(DEG_TO_RAD*(theta + 45 )));
glVertex2f(cos(DEG_TO_RAD*(theta - 45 )), sin(DEG_TO_RAD*(theta - 45 )));
glVertex2f(cos(DEG_TO_RAD*(theta - 135)), sin(DEG_TO_RAD*(theta - 135)));
The comment from Andon below your question is right. You should create the geometry (the vertices) only once and then rotate them by setting the matrix to ModelView and rotate with glRotatef(...). Recreating geometries on each render cycle is a wrong aproach.
I've been experimenting with programs from my text book that involved clipping 2-D polygons using glOrtho and then creating glutWireSpheres in gluPerspective. My goal is to clip half the sphere with a plane, however, I am having trouble clipping 3-D objects. I created a toggle button to show the sphere clipped and unclipped, however, the button instead shows the sphere moving in a ellipse motion I believe.
Here is my drawscene for creating the sphere
double eqn0[4] = {1, 0, 0.0, -60}; // Data for clipping plane 0.
// Choose window.
glutSetWindow(id2);
gluLookAt(0.0, 3.0, 12.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glClipPlane(GL_CLIP_PLANE0, eqn0); // Specify clipping plane 0.
if (isClip0) glEnable(GL_CLIP_PLANE0); // Clip points s.t. z > 0.25.
else glDisable(GL_CLIP_PLANE0);
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
glutWireSphere(1.0, 10, 10);
glPopMatrix();
glFlush();
And here is my toggle
case '0':
if (isClip0 == 0) isClip0 = 1;
else isClip0 = 0;
glutPostRedisplay();
break;
Can someone help me get in the right direction for clipping 3-D objects? Because this will work on 2-D polygons, yet when I try to apply it to spheres, the toggle button doesn't even act like a toggle.
EDIT: Full code:
#include <cmath>
#include <iostream>
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
#endif
#define PI 3.14159265
using namespace std;
// Globals.
static int id1, id2; // Window identifiers.
static int isClip0 = 0; // Is clipping plane 0 enabled?
static int isClip1 = 0; // Is clipping plane 1 enabled?
static int isClip3 = 0; // Is clipping plane 0 enabled?
static int isClip4 = 0; // Is clipping plane 1 enabled?
// Drawing routine for first window.
void drawScene1(void)
{
// Choose window.
glutSetWindow(id1);
glClear(GL_COLOR_BUFFER_BIT);
// A red square.
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex3f(10.0, 10.0, 0.0);
glVertex3f(40.0, 10.0, 0.0);
glVertex3f(40.0, 40.0, 0.0);
glVertex3f(10.0, 40.0, 0.0);
glEnd();
glFlush();
}
// Drawing routine for second window.
void drawScene2(void)
{
double eqn0[4] = {1, 0, 0.0, -1000}; // Data for clipping plane 0.
// Choose window.
glutSetWindow(id2);
gluLookAt(0.0, 3.0, 12.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glClipPlane(GL_CLIP_PLANE0, eqn0); // Specify clipping plane 0.
if (isClip0) glEnable(GL_CLIP_PLANE0); // Clip points s.t. z > 0.25.
else glDisable(GL_CLIP_PLANE0);
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
glutWireSphere(1.0, 10, 10);
glPopMatrix();
glFlush();
}
// Initialization routine for first window.
void setup1(void)
{
// Black background.
glClearColor(0.0, 0.0, 0.0, 0.0);
}
// Initialization routine for second window.
void setup2(void)
{
// Green background.
glClearColor(1.0, 1.0, 1.0, 0.0);
}
// Reshape routine for first window.
void resize1(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Non-square aspect ratio squashes the square.
glOrtho(0.0, 50.0, 0.0, 100.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Reshape routine for second window.
void resize2(int w, int h)
{
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)w/(float)h, 1.0, 50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Keyboard input processing routine shared by both windows.
void keyInput(unsigned char key, int x, int y)
{
switch(key)
{
case 27:
exit(0);
break;
case '0':
if (isClip0 == 0) isClip0 = 1;
else isClip0 = 0;
glutPostRedisplay();
break;
default:
break;
}
}
// Main routine.
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
// First top-level window definition.
glutInitWindowSize(250, 500);
glutInitWindowPosition(100, 100);
// Create the first window and return id.
id1 = glutCreateWindow("windows.cpp - window 1");
// Initialization, display, and other routines of the first window.
setup1();
glutDisplayFunc(drawScene1);
glutReshapeFunc(resize1);
glutKeyboardFunc(keyInput); // Routine is shared by both windows.
// Second top-level window definition.
glutInitWindowSize(250, 500);
glutInitWindowPosition(400, 100);
// Create the second window and return id.
id2 = glutCreateWindow("windows.cpp - window 2");
// Initialization, display, and other routines of the second window.
setup2();
glutDisplayFunc(drawScene2);
glutReshapeFunc(resize2);
glutKeyboardFunc(keyInput); // Routine is shared by both windows.
glutMainLoop();
return 0;
}
Sphere is dealt with in drawScene2
So, after adding a glLoadIdentity() right before the gluLookAt(), the movements will go away (as I already had suggested...). And when one sets a useful clip plane equation, the clipping works as expected, too. As you define a sphere with radius 1 around the object space center, setting
GLdouble eqn0[4] = {1, 0, 0.0, 0.5};
will result in the sphere being clipped at x=-0.5, so 3/4 of it is still visible, as one would expect.