## Feladat:

Sokszögrajzoló: Készítsünk OpenGL programot szabályos sokszög modellezésére.

A kurzormozgató nyilak segítségével interaktívan változtathassuk a szabályos sokszög oldalainak számát és a köré írható kör sugarát. Használjuk ki, hogy a szabályos sokszög csúcsai egy körvonalon helyezkednek el, egyenlő ívekre osztva azt. Az F1 billentyű lenyomásával választhassunk a kitöltött és körvonalas megjelenítési módok között.

## Megoldás:

A programunk felépítése a következő lesz.

- Illesszük be a megfelelő fejléc állományokat,

      #include <GL/glut.h>
      #include <math.h>

  és definiáljuk a globális változókat:

      /* Pi konstans kozelito erteke. */
      #define GL_PI 3.1415f

      /* A szabalyos sokszog csucspontjainak szama. */
      int N = 3;

      /* A sokszog kore irhato kor sugara. */
      double R = 10.0;

      /* Kitoltott vagy korvonalas megjelenites. */
      int filled_display = 1;

- Készítsük el a `main()` függvényt. Inicializáljuk a glut-ot (`glutInit()`) és a megjelenítési módot (`glutInitDisplayMode()`). Hozzunk létre egy ablakot (`glutCreateWindow()`). Állítsuk be mely függvény hívodjon meg, ha átméretezzük az ablakot (`glutReshapeFunc()`), ha lenyomunk egy speciális billentyűt, ebben a programban a kurzormozgató nyilakat (`glutSpecialFunc()`), ha ki kell vagy újra kell rajzolni a képet (`glutDisplayFunc()`). Hozzuk az OpenGL-t a megfelelő állapotba (`SetupRC()`), és indítsuk el az üzenetkezelő ciklust (`glutMainLoop()`).

      int main(int argc, char* argv[])
      {
        /* Inicializalas */
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
        glutCreateWindow("Szabalyos sokszog");

        /* Viszahivhato fuggvenyek beallitasa */
        glutReshapeFunc(ChangeSize);
        glutSpecialFunc(SpecialKeys);
        glutDisplayFunc(RenderScene);

        /* Globalis beallitasok */
        SetupRC();

        /* Vezerles atadasa a GLUT-nak */
        glutMainLoop();

        return 0;
      }

- Írjuk meg a `SetupRC()` függvényt, amely feketére állítja a törlőszínt és sárgára a modellezés színét.

      void SetupRC()
      {
        /* Fekete hatter */
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

        /* Modellezes szinenek beallitasa */
        glColor3f(1.0, 1.0, 0.0);
      }

- A `ChangeSize()` függvény akkor hajtódik végre, amikor átméretezzük a megjelenítő ablakot, és emiatt az OpenGL vetítési paramétereit újra kell számolni. Most a [-25,25] intervallumra állítunk be párhuzamos vetítést úgy, hogy az ablakot minél jobban kitöltse az eredmény. Ennek részleteivel majd máskor foglalkozunk, egyelőre elfogadjuk így ahogy van.

      void ChangeSize(int w, int h)
      {
        GLfloat nRange = 25.0f;

        /* Nullaval nem osztunk */
        if(h == 0)
          h = 1;

        /* Viewport beallitasa az ablak meretere. */
        glViewport(0, 0, w, h);

        /* Projekcios matrix inicializalasa */
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        /* Parhuzamos vetites beallitasa */
        if (w <= h)
          glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
        else
          glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

        /* ModelView matrix inicializalasa */
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
      }

- A `SpecialKeys()` függvényben változtatjuk a globális paramétereket, és újrarajzoltatjuk a képet a `glutPostRedisplay()` meghívásával. FONTOS: Nem szabad meghívni közvetlenül a `RenderScene()` függvényt!

      void SpecialKeys(int key, int x, int y)
      {
        if(key == GLUT_KEY_F1)
          filled_display = !filled_display;

        if(key == GLUT_KEY_UP)
          if(R < 24.9)
            R += 1.0;

        if(key == GLUT_KEY_DOWN)
          if(R > 1.1)
            R -= 1.0;

        if(key == GLUT_KEY_LEFT)
          if(N > 3)
            N --;

        if(key == GLUT_KEY_RIGHT)
          N ++;

        /* Ablak frissitese */
        glutPostRedisplay();
      }

- Szükségünk lesz az előzőleg megismert `DiskApprox()` függvényre.

      void DiskApprox(int n, double radius, float x, float y)
      {
        /*
          n      - hany oldalu szabalyos sokszoggel kozelitunk (n legalább 3)
          radius - a sokszog kore irhato kor sugara
          x, y   - a sokszog kore irhato kor kozeppontjanak koordinatai
        */

        int i;
        GLfloat angle;

        if(n < 3)
          n = 3;

        glBegin(GL_POLYGON);
        for(i = 0, angle = 0.0; i < n; i++, angle += 2.0 * GL_PI / n)
        {
            glVertex2f(x + radius * cos(angle), y + radius * sin(angle));
        }
        glEnd();
      }

- Lássuk a modellezést! A `RenderScene()` függvény hívódik meg, ha erre szükség van. Itt először töröljük a képet (a `SetupRC()` függvényben beállított színnel), majd a globális `filled_display` változó értéke alapján megadjuk a poligon megjelenítési módját.
  A szabályos sokszöget a `DiskApprox()` függvény megfelelő paraméterezésű meghívásával kapjuk.
  A `glutSwapBuffers()` üríti a parancspuffert, vagyis az OpenGL az az összegyűlt modellező parancsokat mindet végrehatja, így az eredmény megjelenik a képernyőn.

      void RenderScene(void)
      {
        /* Ablak torlese az aktualis torloszinnel. */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Poligon megjelenitesi modja. */
        if(filled_display)
          glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        else
          glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

        DiskApprox( N, R, 0.0, 0.0 );

        /* Pufferek csereje, uj kep megjelenitese */
        glutSwapBuffers();
      }

- Kész! Próbáljuk ki! sokszog.c