Reputation: 22270
I'm working a MS paint-like application on OpenGL using Bresenham's midpoint algorithm as homework. So far I can draw lines and ellipses. I lose them all when resizing the window. How can I keep them drawn?
Full code:
#include "GL/glut.h"
#include <stdio.h>
#include <math.h>
int i;
//int mainWindow, subWindow;
int X1, Y1, X2, Y2;
int modoDeDibujo;
int W = 1000, H = 1000;
/*void menuApp (int value)
{
if (value == 1) printf("Linea\n");
if (value == 2) printf("Circulo\n");
if (value == 3) printf("Elipsis\n");
if (value == 4) exit(0);
}
void crearMenu()
{
//inicio Creando el menu
int submenu;
submenu = glutCreateMenu(menuApp);
glutAddMenuEntry("Linea", 1);
glutAddMenuEntry("Elipse",3);
glutAddMenuEntry("Salir",4);
glutCreateMenu(menuApp);
glutAddSubMenu("SubMenu", submenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
//fin Creando el menu
}*/
void renderPoint(void) /*REVISAR ESTO*/
{
glClear (GL_COLOR_BUFFER_BIT);
glBegin (GL_POINTS);
glVertex2f (-0.98, 0.98);
glEnd ();
glFlush ();
}
void renderPoint(double x, double y)
{
//printf("BEFORE TRANSFORM %f\t%f\t# renderPoint\n", x, y);
W = glutGet(GLUT_WINDOW_WIDTH);
H = glutGet(GLUT_WINDOW_HEIGHT);
float X;
float Y;
glBegin (GL_POINTS);
X = (2*x/W) - 1;
Y = (-2*y/H) + 1;
glVertex2f (X, Y);
//printf("TRANSFORMED POINT %f\t%f\t# renderPoint\n", X, Y);
glEnd ();
glFlush ();
}
/*wiki pseudo:
function line(x0, x1, y0, y1) //x1
boolean steep := abs(y1 - y0) > abs(x1 - x0)//x2
if steep then//x3
swap(x0, y0) //x4
swap(x1, y1) //x5
if x0 > x1 then //x6
swap(x0, x1) //x7
swap(y0, y1) //x8
int deltax := x1 - x0 //x9
int deltay := abs(y1 - y0) //x10
int error := deltax / 2 //x11
int ystep //x12
int y := y0 //x13
if y0 < y1 then ystep := 1 else ystep := -1 //x14
for x from x0 to x1 //x15
if steep then plot(y,x) else plot(x,y) //x16
error := error - deltay //x17
if error < 0 then //x18
y := y + ystep //x19
error := error + deltax //x20
*/
void bresenham1(GLint x0, GLint x1, GLint y0, GLint y1) //function line(x0, x1, y0, y1)
{
//double result1 = fabs((double)y1 - y0); //abs(y1 - y0)
//double result2 = fabs((double)x1 - x0); //abs(x1 - x0)
int result1 = abs(y1-y0);
int result2 = abs(x1-x0);
bool steep = (result1 > result2); //boolean steep := abs(y1 - y0) > abs(x1 - x0)
if (steep){ //if steep then
GLint aux1 = x0; //swap(x0, y0)
x0=y0;
y0 = aux1;
GLint aux2 = x1; // swap (x1,y1)
x1=y1;
y1=aux2;
}
if(x0>x1){ // if (x0>x1)
GLint aux3=x0; //swap(x0,x1)
x0=x1;
x1=aux3;
GLint aux4=y0;//swap(y0,y1)
y0=y1;
y1=aux4;
}
int deltax = x1-x0; // deltax = x1-x0
int deltay = abs(y1-y0); // int deltay := abs(y1 - y0) - revisar
int error = (deltax / 2); //int error := deltax / 2
int ystep; // int ystep
int y = y0; //int y := y0
if (y0<y1){ //if y0 < y1 then ystep := 1 else ystep := -1
ystep=1;
}
else {ystep=-1;}
for (int x=x0; x<=x1; x++){ //for x from x0 to x1
if (steep){ // if steep then plot(y,x) else plot(x,y)
renderPoint(y,x);
}
else {
renderPoint(x,y);
}
error = error - deltay; //error := error - deltay
if (error<0) { //if error < 0 then
y = y + ystep; // y := y + ystep
error = error + deltax; //error := error + deltax
} // end if (error<0)
}// end for from x0 to x1
}// end bresenham
void Plot4EllipsePoints(int X, int Y,int CX,int CY){
renderPoint(CX+X, CY+Y); //point in quadrant 1
renderPoint(CX-X, CY+Y); // point in quadrant 2
renderPoint(CX-X, CY-Y); // point in quadrant 3
renderPoint(CX+X, CY-Y); // point in quadrant 4
}
void PlotEllipse (int CX, int CY, int XRadius, int YRadius) {
int X, Y;
int XChange, YChange;
int EllipseError;
int TwoASquare, TwoBSquare;
int StoppingX, StoppingY;
TwoASquare = 2 * XRadius * XRadius;
TwoBSquare = 2 * YRadius * YRadius;
X = XRadius;
Y =0;
XChange = YRadius*YRadius*(1-(2*XRadius));
YChange = XRadius * XRadius;
EllipseError =0;
StoppingX = TwoBSquare*XRadius;
StoppingY = 0;
while(StoppingX >= StoppingY){
Plot4EllipsePoints(X,Y,CX,CY);
Y++;
StoppingY=StoppingY + TwoASquare;
EllipseError= EllipseError+ YChange;
YChange= YChange+ TwoASquare;
if( ((2*EllipseError) + XChange)>0)
{
X--;
StoppingX = StoppingX - TwoBSquare;
EllipseError= EllipseError + XChange;
XChange = XChange + TwoBSquare;
}
}
//1st set of points done, start second set
X=0;
Y= YRadius;
XChange= YRadius*YRadius;
YChange = XRadius*XRadius*(1-2*YRadius);
EllipseError=0;
StoppingX =0;
StoppingY= TwoASquare * YRadius;
while(StoppingX <= StoppingY){ // 2nd set of points, y'<-1
Plot4EllipsePoints(X,Y, CX,CY);
X++;
StoppingX = StoppingX + TwoBSquare;
EllipseError = EllipseError + XChange;
XChange = XChange + TwoBSquare;
if (((2*EllipseError) + YChange)>0){
Y--;
StoppingY = StoppingY - TwoASquare;
EllipseError = EllipseError + YChange;
YChange = YChange + TwoASquare;
}
}
}
void renderAll (void)
{
/*glutSetWindow(mainWindow);
glutPostRedisplay();
glutSetWindow(subWindow);
glutPostRedisplay();*/
}
void movimiento(int boton, int estado, int x, int y)
{
if((estado == GLUT_DOWN) && (boton == GLUT_LEFT_BUTTON))//mouse down
{
X1 = x; Y1 = y;
PlotEllipse (x, y, 200, 100);
renderPoint(x,y);
}
if((estado == GLUT_UP) && (boton == GLUT_LEFT_BUTTON))//mouse up
{
//printf(" Up|x:%d, y:%d\n",x,y);
X2 = x; Y2 = y;
//renderLine();
bresenham1(X1,X2,Y1,Y2);
//PRUEBA USANDO LA PRIMITIVA DE OPENGL
glBegin( GL_LINES );
glEnd();
//renderPoint(x, y);
}
}
void MouseMove(int x, int y)
{
//printf("x:%d | y:%d\n", x,y);
X2 = x; Y2 = y;
//renderLine();
//bresenham1(X1, Y1, X2, Y2);
}
void teclado(unsigned char key, int x, int y)
{
if(key==1){
modoDeDibujo=1; // dibuja lineas
printf("Modo de dibujo: linea");
}
if (key==2){
modoDeDibujo=2; //dibuja elipses
}
if(key == 27)exit(0);
}
void especiales(int key, int x, int y)
{
if(key == GLUT_KEY_F1) exit(0);
}
static void
key(unsigned char k, int x, int y)
{
switch (k) {
case 27: /* Escape */
exit(0);
break;
default:
return;
}
glutPostRedisplay();
}
int main (int argc, char *argv [])
{
i = 0;
//inicializa las operaciones de OpenGL/GLUT, db cr antes de usar funciones GLUT
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition (100, 100);
glutInitWindowSize (W, H);
//Crea una ventana de Opengl
glutCreateWindow ("tarea");
glutDisplayFunc (renderPoint);
glutMouseFunc(movimiento);
glutKeyboardFunc(teclado);//teclas ASCII
glutSpecialFunc(especiales);//captura las teclas [f1..f12]
//glutPassiveMotionFunc(pasivo);
glutKeyboardFunc(key);
glutMotionFunc(MouseMove);
//crearMenu();
glutMainLoop ();
}
Upvotes: 2
Views: 2698
Reputation: 5575
First of all , you need to arrange the code. You must have one and only one display function, that clears the buffer,calls the other draw-functions and flushes them to the screen ( or swaps the buffer if you are using a double buffer).
On resizing the window,GLUT will call the Display Function which is renderPoint() as you know :
glutDisplayFunc (renderPoint);
renderPoint clears the buffer before redrawing the "points" , for example :
void renderPoint(void) /*REVISAR ESTO*/
{
glClear (GL_COLOR_BUFFER_BIT);
glBegin (GL_POINTS);
glVertex2f (-0.98, 0.98);
glEnd ();
glFlush ();
}
Since the buffer has been cleared , all the points that are drawn outside the function renderPoint ( the points of circles, the points of lines .. ) has no meaning , because you did not call them from the "main display function which is renderPoint.
How to keep the points on the screen ?
You must store the points ( any point you want to draw ) in a buffer such as an array , a dynamic array, std::vector or anything else. in the display function , write a loop statement to visit each point and extract the x and y .. then draw them.
for example , instead of the above function , replace it with :
class MyPoint {
public:
float x;
float y;
MyPoint(float x, float y)
{
this->x = x;
this->y = y;
} };
#include <vector>
std::vector<MyPoint> testPoints;
void renderPoint(void) /*REVISAR ESTO*/ {
testPoints.push_back(MyPoint(-0.58,0.58));
testPoints.push_back(MyPoint(0.58,0.58));
testPoints.push_back(MyPoint(0.58,-0.58));
glClear (GL_COLOR_BUFFER_BIT);
glPointSize(2);
glBegin (GL_POINTS);
for(int i=0;i<testPoints.size();i++)
{
glVertex2f (testPoints[i].x, testPoints[i].y);
}
glEnd ();
glFlush ();
}
as you can see , by using a dynamic array such as (std::vector) to store the points and by using a for loop statement , we able to keep the three points visible.
what else ?
do the same method with other shapes , so that for each "mouse click
" event , you may add or push_back
two points represents a line end points in an array or std::vector called lineArray
. in the display function
, make a for loop statement to draw each line after extracting the two line points.
you should use glutReshapeFunc
and glViewport
to make sure that the viewport has the same dimenstions as the window after the resizing event. and I think that gluOrtho2d
is more elegant than trying to mapping from Windows coordinates space to OpenGL coordinates space
arrange your code , so that you just use one display function.
Your program could be Something like this:
void drawTestPoints()
{
for(int i=0;i<length;i++)
{
renderPoint(pointsArray[i].x,pointsArray[i].y);// vector of points/(MyPoint)
}
}
void drawLines()
{
for(int i=0;i<length;)
{
MyPoint startPoint = linesArray[i];
MyPoint endPoint = linesArray[i+1];
bresenham1(startPoint.x,endPoint.x,startPoint.y,endPoint.y);
i+=2;
}
}
void drawAll()
{
glClear (GL_COLOR_BUFFER_BIT);
drawTestPoints();
drawLines();
drawOtherShapes();
glFlush();
}
.
.
.
// in the main func:
glutDisplayFunc (drawAll);
==
Upvotes: 4
Reputation: 64223
Here is a quick example for windows : http://www.falloutsoftware.com/tutorials/gl/gl2.htm
Upvotes: 2
Reputation: 81459
Don't think of it as "keeping them drawn". Think instead in terms of events and "when do I need to redraw my objects".
For this you will need to handle the resize event and rerun your drawing code. I'm also guessing that your objects might not redraw themselves after another application is moved over them, or if it is moved off screen a little and then brought back. If this is the case you'll need to figure out what events to handle that will cause a redraw as well.
Upvotes: 3