![]() |
are you ready for a mindfuck? |
|
....::::Menu::::.... ---------------------------...::About::... ...::Articles::... ...::Contact::... ...::Home & News::... ...::Links & Credits::... --------------------------- --------------------------- |
Polygonby Elie De BrauwerGoal of this fileThis file ends our basic knowledge about 2 dimensional drawings, we'll create a color palette and create a colored polygon that is created by the user. The transformation basics will also be explained here. So a base is available that can be used when we switch to 3d graphics. History of this file
What will be doneIn this article I will create an application with a color palette from which the user can select some colors and draw a polygon by clicking a number of points in the window. In order to follow you need to have some knowledge about dynamical memory allocation. Drawing
In a previous article about the creation of a circle I enumerated all possible parameters glBegin() could
take. GL_LINE_LOOP and GL_LINES were already used in previous articles now we'll use
GL_POLYGON and GL_QUADS. We will also see a new command (glColor3f()) which we can use
between glBegin() and glEnd(). glBegin(GL_QUADS); glColor3f(1,0,0); glVertex2f( 1.0, 1.0); glVertex2f(-1.0, 1.0); glVertex2f(-1.0,-1.0); glVertex2f( 1.0,-1.0); glEnd(); glColor3f() takes three arguments, a red, green and blue value in the interval [0,1]. The other functions we
called we already know from previous articles.
The image was created using dia. The polygons on the
left are allowed the ones on the right are not allowed. Why does OpenGL makes such a fuss about these little differences ?
Well the answer is simple, speed. By assuming that all polygons are of the simpler type a big advantage in speed is made but
the more complex polygons are displayed in a wrond way. This is something the developer (yes, that's you) has to think about
because OpenGL will just do something wrong without giving you a warning. Ok you might perhaps not get the point which polygon
is displayed correctly and which one is not. Well this is your lucky day because the application that is described in this
article let's the user pick a number of points, even assign each point an other color and after each click OpenGL will do
the drawing of the polygon and if you created a wrong polygon you will see OpenGL do something wrong. Polygonmodes and shademodel
First let's say something about a function called glPolygonMode(GLenum face, GLenum mode). This function takes two
parameters, the face parameter can be GL_BACK, GL_FRONT and GL_FRONT_AND_BACK and the mode paramter can be
GL_LINE, GL_POINT or GL_FILL (which is the default). Face defines to which polygons the mode applies. When
the face is GL_BACK, the mode only applies to back facing polygons (and the same goes for GL_FRONT and
GL_FRONT_AND_BACK). Putting it all together
Below you can see the sourcecode, you can see it uses new and delete to dynamically allocate memory to store more s_point
data when the users clicks on the screen. When you run the program you will see that a polygon is draw as soon as three or more
points are entered. You can use the keys w, p and f to change the glPolygonMode() to wireframe mode, point mode and fill
mode. You can use the keys s and b to change the glShadeModel to smooth shading and flat shading. Some screenshots
A not valid filled polygon with smooth shading
The same not valid polygon with smooth shading in wirefrime mode
The filled polygon with flat shading
An example of a valid polygon, filled mode and smooth shading.
And the same polygon now in wireframe mode. The program
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <GL/glut.h>
using namespace std;
// typedefs
typedef unsigned char uchar;
// constants
const int BOXSIZE = 20;
const int NUMCOLORS = 7;
// struct
struct s_point{
int x, y, color;
};
// static vars
static s_point *points = NULL;
static int cur_color = 0;
static int num_points = 0;
static int height;
// callbacks
void keyb(uchar key, int x, int y);
void disp(void);
void resize(int x, int y);
void mouse(int button, int state, int x, int y);
// prototypes
void drawQuad(int x, int y,int delta);
////////////////////////////////
// main
int main(int argc,char **argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(500,500);
glutInitWindowPosition(100,100);
glutCreateWindow("Polygon.cpp");
glClearColor(0.0,0.0,0.0,0.0);
glutKeyboardFunc(keyb);
glutDisplayFunc(disp);
glutReshapeFunc(resize);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
////////////////////////////////////////////////
// mouse
void mouse(int button, int state, int x, int y){
// if left mouse down
if(button == GLUT_LEFT && state == GLUT_DOWN){
// are we clicking in the pallette ?
if((x < BOXSIZE) && (abs(y-height) < (NUMCOLORS * BOXSIZE))){
// if we are in the pallette, change the current color
cur_color = abs(y-height)/BOXSIZE;
// or have we clicked in the screen ?
}else{
s_point * temp = new s_point[num_points+1];
// copy the old to a temporary
for(int i=0;i<(num_points);i++){
temp[i].x = points[i].x;
temp[i].y = points[i].y;
temp[i].color = points[i].color;
}
// save the new one
temp[num_points].x = x;
temp[num_points].y = height - y;
temp[num_points].color = cur_color;
// increment the number of points
num_points++;
// delete the old
delete [] points;
// make the temporary the current one
points = temp;
// ask for a redisplay
glutPostRedisplay();
}
}
}
///////////////////////////////////
// keyb
void keyb(uchar key, int x, int y){
switch(key){
case 'q':
delete[] points;
exit(0);
break;
case 'w':
cout << "Wireframe mode on " << endl;
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glutPostRedisplay();
break;
case 'p':
cout << "Point mode on " << endl;
glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);
glutPostRedisplay();
break;
case 'f':
cout << "Fill mode on " << endl;
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glutPostRedisplay();
break;
case 's':
cout << "Smooth shading " << endl;
glShadeModel(GL_SMOOTH);
glutPostRedisplay();
break;
case 'b':
cout << "Flat shading " << endl;
glShadeModel(GL_FLAT);
glutPostRedisplay();
break;
}
};
////////////////
// disp
void disp(void){
// define colors
static float colorarray[NUMCOLORS][3] =
{
{1.0,1.0,1.0},
{0.0,1.0,1.0},
{0.0,0.0,1.0},
{1.0,1.0,0.0},
{1.0,0.0,0.0},
{0.0,1.0,0.0},
{1.0,0.0,1.0}
};
glClear(GL_COLOR_BUFFER_BIT);
// draw the palette
int ypos = 0;
for(int i=0;i<NUMCOLORS;i++){
glColor3fv(colorarray[i]);
drawQuad(0,ypos,BOXSIZE);
ypos+=BOXSIZE;
}
glBegin(GL_POLYGON);
for(int i=0;i<num_points;i++){
glColor3fv(colorarray[points[i].color]);
glVertex2f(points[i].x,points[i].y);
}
glEnd();
glutSwapBuffers();
}
//////////////////////////////////////
// drawQuad
void drawQuad(int x, int y, int delta){
glBegin(GL_QUADS);
glVertex2f(x,y);
glVertex2f(x+delta,y);
glVertex2f(x+delta,y+delta);
glVertex2f(x,y+delta);
glEnd();
}
//////////////////////////
// resize
void resize(int x, int y){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,x,0,y);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
height = y;
}
You can always download the sourcecode here Putting it even more togetherIt would be a nice exercise to implement the following features:
|