opengl: как сохранить объекты в окне при его изменении - PullRequest
2 голосов
/ 15 октября 2010

Я работаю в MS-подобном приложении под OpenGL, используя алгоритм средней точки Брезенхэма в качестве домашней работы. До сих пор я могу рисовать линии и эллипсы. Я теряю их все при изменении размера окна. Как я могу держать их нарисованными?

Полный код:

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


}

Ответы [ 3 ]

4 голосов
/ 15 октября 2010

Прежде всего, вам нужно расположить код.У вас должна быть одна и только одна функция отображения, которая очищает буфер, вызывает другие функции рисования и сбрасывает их на экран (или заменяет буфер, если вы используете двойной буфер).

При изменении размераОкно, GLUT вызовет функцию отображения, которая является renderPoint (), как вы знаете:

glutDisplayFunc (renderPoint);

renderPoint очищает буфер перед перерисовкой «точек», например:

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

Поскольку буфер был очищен, все точки, нарисованные вне функции renderPoint (точки окружностей, точки линий ...) не имеют смысла, потому что вы не вызывали их из «основного экрана»функция renderPoint.

Как сохранить точки на экране?

Вы должны хранить точки (любую точку, которую хотите нарисовать) в буфере, например:массив, динамический массив, std :: vector или что-нибудь еще в функции отображения, напишите оператор цикла для посещения каждой точки и извлеките x и y .. затем нарисуйте их. * 101Например, 7 *

вместо вышеуказанной функции замените ее на:

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

, как вы можете видеть, используя динамический массив, такой как (std :: vector), для хранения точек ииспользуя оператор цикла for, мы можем сохранить три видимые точки.

что еще?

  • сделать тот же метод с другими фигурами, так что для каждого события "mouse click" вы можете add or push_back две точки представлять конечные точки линии в массиве или std :: vector с именем lineArraydisplay function создайте оператор цикла for, чтобы нарисовать каждую линию после извлечения двух точек.

  • вам следует использовать glutReshapeFunc и glViewport, чтобы убедиться, что область просмотраимеет те же размеры, что и окно после события изменения размера.и я думаю, что gluOrtho2d более элегантно, чем пытаться отобразить из пространства координат Windows в пространство координат OpenGL

  • упорядочить ваш код, так что вы просто используете одну функцию отображения.

Ваша программа может выглядеть примерно так:

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

==

3 голосов
/ 15 октября 2010

Не думайте об этом, как о том, чтобы «держать их в покое». Вместо этого подумайте о событиях и «когда мне нужно перерисовать мои объекты».

Для этого вам нужно обработать событие изменения размера и повторно запустить код для рисования. Я также предполагаю, что ваши объекты могут не перерисовать себя после того, как над ними будет перемещено другое приложение, или если оно будет немного перемещено за пределы экрана, а затем восстановлено. В этом случае вам необходимо выяснить, какие события обрабатывать, что также приведет к перерисовке.

2 голосов
/ 15 октября 2010

Вот краткий пример для Windows: http://www.falloutsoftware.com/tutorials/gl/gl2.htm

...