2010-10-15 7 views
2

Je travaille sur MS OpenGL en utilisant l'algorithme de Bresenham comme devoirs. Jusqu'à présent, je peux dessiner des lignes et des ellipses. Je les perds tous lorsque je redimensionne la fenêtre. Comment puis-je les garder dessinés?opengl: comment conserver les objets dans la fenêtre lors de son redimensionnement

code complet:

#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(); 


} 

Répondre

4

Tout d'abord, vous devez organiser le code. Vous devez avoir une et une seule fonction d'affichage, effacer le tampon, appeler les autres fonctions de dessin et les vider à l'écran (ou échanger le tampon si vous utilisez un double tampon).

Le redimensionnement de la fenêtre, GLUT appellera la fonction d'affichage qui est renderPoint() comme vous le savez:

glutDisplayFunc (renderPoint); 

renderPoint efface la mémoire tampon avant de redessiner les "points", par exemple:

void renderPoint(void) /*REVISAR ESTO*/ 
{ 
    glClear (GL_COLOR_BUFFER_BIT); 
    glBegin (GL_POINTS); 
     glVertex2f (-0.98, 0.98); 
    glEnd(); 
    glFlush(); 
} 

Depuis que le tampon a été effacé, tous les points qui sont dessinés en dehors de la fonction renderPoint (les points de cercles, les points de lignes ..) n'ont aucune signification, parce que vous ne les appelez pas du Fonction ay qui est renderPoint.

Comment garder les points sur l'écran?

Vous devez stocker les points (tout point que vous voulez dessiner) dans un tampon tel qu'un tableau, un tableau dynamique, un vecteur std :: ou autre chose. dans la fonction d'affichage, écrivez une déclaration de boucle pour visiter chaque point et extraire les x et y .. puis dessinez-les.

par exemple, au lieu de la fonction ci-dessus, le remplacer par: enregistrer les points

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(); 
} 

comme vous pouvez le voir, en utilisant un tableau dynamique tel que (std :: vecteur) et en utilisant un pour la déclaration de boucle, nous pouvons garder les trois points visibles.

quoi d'autre?

  • font la même méthode avec d'autres formes, de sorte que pour chaque « mouse click » événement, vous pouvez add or push_back deux points représente un point de fin de ligne dans un tableau ou std :: vecteur appelé lineArray. dans le display function, faites une instruction for loop pour dessiner chaque ligne après avoir extrait les deux points de ligne. Vous devez utiliser glutReshapeFunc et glViewport pour vous assurer que la fenêtre a les mêmes dimensions que la fenêtre après l'événement de redimensionnement.et je pense que gluOrtho2d est plus élégant que d'essayer de mapper de l'espace de coordonnées Windows à l'espace de coordonnées OpenGL

  • d'organiser votre code, de sorte que vous utilisez simplement une fonction d'affichage.

Votre programme pourrait être quelque chose comme ceci:

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); 

==

+0

Merci, très détaillé, même si je ne sais pas comment organiser ce code pour utiliser une seule fonction d'affichage. Quel est le problème avec l'approche actuelle que j'utilise? – andandandand

+0

Pour toutes les applications GLUT, il n'y a qu'une seule fonction d'affichage qui sera appelée après (redimensionnement/repeindre les événements se produisent). le tampon sera effacé et OpenGL redessinera les points sur le tampon. A votre place, les points seraient supprimés si l'événement de repeint se produisait, donc utilisez la fonction d'affichage comme fonction d'affichage principale qui appelle d'autres fonctions qui dessinent d'autres formes, ces fonctions ont des instructions for loop pour dessiner les points qui sont stockés dans un tableau. – Abdullah

+0

J'ai ajouté un exemple dans le dernier paragraphe de la réponse (pour clarifier ce que je voulais dire par arrangement). – Abdullah

3

Ne pensez pas comme "les tenir tirés". Pensez plutôt en termes d'événements et «quand dois-je redessiner mes objets». Pour cela, vous devrez gérer l'événement de redimensionnement et relancer votre code de dessin. Je devine aussi que vos objets pourraient ne pas se redessiner après qu'une autre application soit déplacée sur eux, ou si elle est légèrement déplacée hors de l'écran puis ramenée. Si c'est le cas, vous aurez besoin de comprendre quels événements gérer cela provoquera un redessin.

+0

comment puis-je exécuter à nouveau le code de dessin ? Dois-je garder une pile avec les opérations que j'ai faites? Si oui, pourriez-vous fournir un exemple? – andandandand

+0

@omgzor: Ma réponse est de très haut niveau et conceptuelle. Consultez les réponses de BugKiller et VJo pour les détails détaillés. Et encore une idée conceptuelle: ne pensez pas à cela comme une pile d'opérations. Pensez à une collection (tableau) de primitives (objets dessinés) qui doivent être redessinées fréquemment. –

Questions connexes